Elasticsearch:Levenshtein 排序

标签 elasticsearch

我有一个足够有效的查询,但我想通过在查询参数和相关字段之间使用 levenshtein 对结果进行排序。

现在我在 ES 中进行查询,然后在我的应用程序中进行排序。现在我正在测试脚本字段。这是脚本

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 .这是可以理解的。

我的问题是,如何在 elasticsearch 中执行我需要的操作(按 levenshtein 对结果进行排序),从而避免应用程序中的开销。 我可以为此使用 lucene 表达式吗?你有例子吗?有其他方法可以实现吗?

我正在使用 ElasticSearch 1.7.5 作为一项服务。所以 native 插件不应该是第一个解决方案(我不知道即使它可能,我将不得不与我的提供商核实,但如果它是唯一可行的解​​决方案我会这样做)。

更新

所以似乎一个好的解决方案是将它保存在config/scripts 文件夹中,因为它会被编译一次https://www.elastic.co/blog/running-groovy-scripts-without-dynamic-scripting .脚本可以被索引而不是保存它 https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html .这对我的用例来说要方便得多。这在脚本编译方面是否具有相同的行为?会不会只编译一次?

最佳答案

请务必注意,Groovy 在 Elasticsearch 5.x 中已弃用,并将在 Elasticsearch 6.0 中删除。您要么想看看使用 Painless 脚本来替换此功能,要么创建一个可能使用 Lucene 的 LuceneLevenshteinDistance 为您执行此操作的 native Java 脚本。

您的脚本也很可怕,因为它添加了许多循环(大部分被 Groovy 助手隐藏)和可能大内存分配。我严重怀疑它的大规模性能。

我还注意到脚本中存在 %s,我认为这意味着您自己的代码会动态替换字段名称。为此,您应该始终使用params,然后将该参数用作脚本中的变量。这避免了必须为每个字段名称编译一个脚本版本。 (我希望您必须这样做才能使其基于文件)

Does this have the same behaviour regarding the compilation of the script?

是的,基于文件的脚本是最安全的(因为它们需要访问机器本身才能安装)。编译基于文件的脚本,就像内联脚本和基于索引的脚本一样。

基于文件的脚本的缺点是您需要将它们添加到每个节点。不是那样,但是每个节点都需要相同版本的脚本。这意味着,如果您选择更新它,那么最好添加一个新脚本并引用它,而不是替换它。

File-based scripts are picked up every 60 seconds by default .

Will it be compiled only once?

是的,每个节点。

关于Elasticsearch:Levenshtein 排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39443049/

相关文章:

amazon-web-services - Amazon Elasticsearch 集群的正确访问策略

elasticsearch - 将数据从PostgreSQL索引到Elasticsearch

Spring数据elasticSearch使用findOne返回null

http - cpprestsdk http凭据设置获取401错误

elasticsearch - 如何禁用elasticsearch http模块?

elasticsearch - 根据 Elasticsearch 中文档的键按优先级过滤

java - 如何使用 spring-data-elasticsearch 中的聚合获取elasticsearch json响应?

elasticsearch - 如何在Elasticsearch中基于索引数据搜索和检索数据

elasticsearch - 让kibana 4发送警报或在特定条件下采取措施的任何方式

java - Docker:无法从 Spring Boot docker 镜像连接到 Elasticsearch