Elasticsearch: сортировка по Левенштейну
У меня есть запрос, который работает достаточно, но я хочу сортировать результаты этого, используя levenshtein между параметром запроса и рассматриваемым полем.
Сейчас я делаю запрос в ES, а затем сортирую в своем приложении. Сейчас я тестирую поле script в сортировке. Это script
import org.elasticsearch.common.logging.*;
ESLogger logger = ESLoggerFactory.getLogger('levenshtein_script');
def str1 = '%s'.split(' ').sort().join(' ');
def str2 = doc['%s'].values.join(' '); //Needed since the field is analyzed. This will change when I reindex the data.
def dist = new int[str1.size() + 1][str2.size() + 1]
(0..str1.size()).each { dist[it][0] = it }
(0..str2.size()).each { dist[0][it] = it }
(1..str1.size()).each { i ->
(1..str2.size()).each { j ->
dist[i][j] = [dist[i - 1][j] + 1, dist[i][j - 1] + 1, dist[i - 1][j - 1] + ((str1[i - 1] == str2[j - 1]) ? 0 : 1)].min()
}
}
def result = dist[str1.size()][str2.size()]
logger.info('Query param: ['+str1+'] | Term: ['+str2+'] | Result: ['+result+']');
return result;
В основном это шаблон (проверьте% s), что я заполняю свое приложение следующим образом
sortScript = String.format(EDIT_DISTANCE_GROOVY_FUNC, fullname, FULLNAME_FIELD_NAME);
Проблема заключается в том, что http://code972.com/blog/2015/03/84-elasticsearch-one-tip-a-day-avoid-costly-scripts-at-all-costs. Что понятно.
Мой вопрос: как я могу делать то, что мне нужно (сортировать результаты по levenshtein) внутри elasticsearch, поэтому я могу избежать накладных расходов в своем приложении.
Могу ли я использовать выражения lucene для этого? У вас есть пример? Есть ли другой способ, которым я могу это сделать?
Я использую ElasticSearch 1.7.5 как услугу. Поэтому родные плагины не должны быть первым решением (я не знаю, даже если это возможно, мне нужно будет проверить у моего провайдера, но если это единственное жизнеспособное решение, я сделаю именно это).
UPDATE
Итак, хорошим решением было бы сохранить его в папке config/scripts
, поскольку он будет скомпилирован один раз https://www.elastic.co/blog/running-groovy-scripts-without-dynamic-scripting. script можно индексировать вместо сохранения https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html. Это гораздо удобнее для моего использования. Имеет ли такое поведение поведение компиляции script? Будет ли он компилироваться только один раз?
Ответы
Ответ 1
Важно отметить, что Groovy устарел в Elasticsearch 5.x, и он будет удален в Elasticsearch 6.0. Вы либо захотите взглянуть на использование сценариев Painless, чтобы заменить эту функциональность, либо создать родной Java script, который, возможно, использует Lucene LuceneLevenshteinDistance
, чтобы сделать это для вас.
Ваш script также довольно пугающий, поскольку он добавляет несколько циклов (в основном скрытых помощниками Groovy) и потенциально больших распределений памяти в миксе. Я серьезно сомневаюсь в его производительности в масштабе.
Я также заметил наличие %s
в script, которое, как я полагаю, означает, что ваш собственный код динамически заменяет имя поля. Вы всегда должны использовать params
для этой цели, а затем использовать параметр как переменную в script. Это позволяет избежать компиляции версии script для каждого имени поля. (Я ожидаю, что вы должны сделать это, чтобы сделать его основанным на файлах)
Имеет ли такое поведение поведение компиляции script?
Да, скрипты на основе файлов являются наиболее безопасными (потому что они требуют доступа к самому компьютеру для установки). Файловые скрипты скомпилированы, как встроенные и индексированные скрипты.
Недостатком скриптов, основанных на файлах, является то, что вам нужно добавить их ко всем node. Не на этом, но для каждого node нужна такая же версия script. Это означает, что если вы когда-нибудь захотите его обновить, лучше добавить новый script и ссылаться на него, а не на его замену.
Файловые сценарии выбираются каждые 60 секунд по умолчанию.
Будет ли он компилироваться только один раз?
Да, за node.