Подобная проблема поиска изображения
- Миллионы изображений pHash 'ed и сохранены в Elasticsearch.
- Формат "11001101... 11" (длина 64), но может быть изменен (лучше не).
Учитывая хеш изображения изображения "100111..10", мы хотим найти все подобные хэш-изображения в индексе Elasticsearch в пределах расстояния до 8.
Конечно, запрос может возвращать изображения с большим расстоянием, чем 8, и script в Elasticsearch или снаружи может фильтровать результирующий набор. Но общее время поиска должно быть не более 1 секунды.
Наше текущее отображение
В каждом документе есть вложенное поле images
, содержащее хэш изображений:
{
"images": {
"type": "nested",
"properties": {
"pHashFingerprint": {"index": "not_analysed", "type": "string"}
}
}
}
Наше плохое решение
Факт: Нечеткий запрос Elasticsearch поддерживает расстояние Левенштейна только от max 2.
Мы использовали пользовательский токенизатор для разделения 64-битной строки на 4 группы по 16 бит и 4-х группового поиска с четырьмя нечеткими запросами.
Анализатор:
{
"analysis": {
"analyzer": {
"split4_fingerprint_analyzer": {
"type": "custom",
"tokenizer": "split4_fingerprint_tokenizer"
}
},
"tokenizer": {
"split4_fingerprint_tokenizer": {
"type": "pattern",
"group": 0,
"pattern": "([01]{16})"
}
}
}
}
Затем новое сопоставление полей:
"index_analyzer": "split4_fingerprint_analyzer",
Затем запрос:
{
"query": {
"filtered": {
"query": {
"nested": {
"path": "images",
"query": {
"bool": {
"minimum_should_match": 2,
"should": [
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "0010100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "1010100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "0110100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "1110100100111001",
"fuzziness": 2
}
}
}
]
}
}
}
},
"filter": {}
}
}
}
Обратите внимание, что мы возвращаем документы, которые имеют соответствующие изображения, а не сами изображения, но это не должно сильно меняться.
Проблема заключается в том, что этот запрос возвращает сотни тысяч результатов даже после добавления других фильтров для конкретных доменов, чтобы уменьшить начальный набор. script имеет слишком много работы, чтобы снова вычислить расстояние для хамминга, поэтому запрос может занять несколько минут.
Как и ожидалось, при увеличении minimum_should_match
до 3 и 4 возвращается только подмножество изображений, которые должны быть найдены, но результирующий набор является небольшим и быстрым. Ниже 95% необходимых изображений возвращаются с помощью minimum_should_match
== 3, но нам нужно 100% (или 99,9%), как с minimum_should_match
== 2.
Мы пробовали аналогичные подходы с n-граммами, но все же не так много успехов в том, что слишком много результатов.
Любые решения других структур данных и запросов?
Edit
Мы заметили, что в нашем процессе оценки была ошибка, а minimum_should_match
== 2 возвращает 100% результатов. Однако время обработки занимает в среднем 5 секунд. Мы увидим, стоит ли оптимизировать script.