我有一个充分的查询,但我想通过在查询参数和相关字段之间使用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;
Run Code Online (Sandbox Code Playgroud)
基本上这是我填写我的应用程序的模板(检查%s)
sortScript = String.format(EDIT_DISTANCE_GROOVY_FUNC, fullname, FULLNAME_FIELD_NAME);
Run Code Online (Sandbox Code Playgroud)
问题是这个http://code972.com/blog/2015/03/84-elasticsearch-one-tip-a-day-avoid-costly-scripts-at-all-costs.这是可以理解的.
我的问题是,我怎样才能在弹性搜索中做我需要的(按levenshtein排序结果),这样我就可以避免应用程序的开销.我可以使用lucene表达式吗?你有一个例子吗?还有其他方法可以实现这一目标吗?
我正在使用ElasticSearch 1.7.5作为服务.所以原生插件不应该是第一个解决方案(我不知道即使它是可能的,我也必须与我的提供商核实,但如果它是唯一可行的解决方案,我会这样做).
UPDATE
所以似乎一个很好的解决方案是将它保存在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 脚本来替换此功能,要么创建一个可能使用 LuceneLuceneLevenshteinDistance来为您执行此操作的本机 Java 脚本。
您的脚本也非常可怕,因为它添加了许多循环(大部分被 Groovy 助手隐藏)和潜在的大量内存分配。我对其规模化表现抱有严重怀疑。
%s我还注意到脚本中存在,我认为这意味着您自己的代码会动态替换字段名称。您应该始终用于params此目的,然后将该参数用作脚本中的变量。这避免了必须为每个字段名称编译脚本的版本。(我希望你必须这样做才能使其基于文件)
这对于脚本的编译有相同的行为吗?
是的,基于文件的脚本是最安全的(因为它们需要访问计算机本身才能安装)。基于文件的脚本被编译,就像内联脚本和基于索引的脚本一样。
基于文件的脚本的缺点是您需要将它们添加到每个节点。不是这样,但每个节点都需要相同版本的脚本。这意味着,如果您选择更新它,那么最好添加新脚本并引用它,而不是替换它。
只会编译一次吗?
是的,每个节点。
| 归档时间: |
|
| 查看次数: |
1076 次 |
| 最近记录: |