我有一个Elasticsearch索引,文档结构如下。
{
"id": "foo",
"tags": ["Tag1", "Tag2", "Tag3"],
"special_tags": ["SpecialTag1", "SpecialTag2", "SpecialTag3"],
"reserved_tags": ["ReservedTag1", "ReservedTag2", "Tag1", "SpecialTag2"],
// rest of the document
}
字段tags
、special_tags
和reserved_tags
分别存储,以供多种使用情况使用。在其中一个查询中,我希望按所有三个字段中搜索标记的出现次数对文档进行排序。例如,如果我使用三个标记Tag1
、Tag4
和SpecialTag3
进行搜索,则在上述文档中出现的总次数为2。使用此数字,我想在此文档中添加自定义分数并按分数排序。
我已经在使用function_score
了,因为评分所依赖的其他属性很少。为了计算匹配的数字,我尝试了如下的无痛脚本。
def matchedTags = 0;
def searchedTags = ["Tag1", "Tag4", "SpecialTag3"];
for (int i = 0; i < searchedTags.length; ++i) {
if (doc['tags'].contains(searchedTags[i])) {
matchedTags++;
continue;
}
if (doc['special_tags'].contains(searchedTags[i])) {
matchedTags++;
continue;
}
if (doc['reserved_tags'].contains(searchedTags[i])) {
matchedTags++;
}
}
// logic to score on matchedTags (returning matchedTags for simplicity)
return matchedTags;
这按预期运行,但是非常慢。我假设ES必须计算每个文档的出现次数,并且不能在这里使用索引。(如果有人能说明这将如何在内部工作,或者提供文档/资源链接,那将是很有帮助的。)
我想有两个评分函数。
1.评分作为发生次数的函数
1.出现次数越多,得分越高。这基本上与1相同,但重复出现的次数将被计入。
有没有什么方法可以让我同时获得更快的搜索和自定义评分使用脚本的好处?
任何帮助都很感激。谢谢。
1条答案
按热度按时间nmpmafwu1#
我们使用位集来解决这个问题。我们最终创建了一个标签位集,其中文档中的所有标签(
tags
,special_tags
等)都有一个set位,其余的标签则为clear位。这被存储为一个大整数。这就像是一个压缩版本的所有标签,我们在一个文档中用位来表示。应用程序知道哪个位是哪个标签。在计算匹配标签的同时,我们创建一个为所有搜索到的标签设置的位集。然后在轻松的脚本中,我们将两个位集都转换为大整数,进行位与并计算设置位的数量。