我听从了 Rohit 的建议,实现了Elasticsearch script filter。你需要configure your Elasticsearch server to allow dynamic (inline) Groovy scripts。
这是 Groovy 脚本过滤器的代码:
def label_map = labels.collectEntries { entry -> [entry, 1] };
def count = 0;
for (def label : doc['label'].values) {
if (!label_map.containsKey(label)) {
return 0
} else {
count += 1
}
};
return count
要在 Elasticsearch 查询中使用它,您要么需要转义所有换行符,要么将脚本放在一行中,如下所示:
def label_map = labels.collectEntries { entry -> [entry, 1] }; def count = 0; for (def label : doc['label'].values) { if (!label_map.containsKey(label)) { return 0 } else { count += 1 } }; return count
这是一个与我所做的非常相似的 Elasticsearch 查询,包括脚本过滤器:
POST /documents/_search
{
"fields": [
"id",
"name",
"label",
"description"
],
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"bool": {
"minimum_should_match": 1,
"should" : {
"term" : {
"description" : "fine"
}
}
}
},
"filter": {
"script": {
"script": "def label_map = labels.collectEntries { entry -> [entry, 1] }; def count = 0; for (def label : doc['label'].values) { if (!label_map.containsKey(label)) { return 0 } else { count += 1 } }; return count",
"lang": "groovy",
"params": {
"labels": [
"foo",
"bar",
"qux",
"zip",
"baz"
]
}
}
}
}
},
"functions": [
{
"filter": {
"query": {
"match": {
"label": "qux"
}
}
},
"boost_factor": 25
}
],
"score_mode": "multiply"
}
},
"size": 10
}
我的实际查询需要将脚本过滤器与函数分数查询结合起来,这很难弄清楚该怎么做,所以我将其作为示例包含在此处。
这样做是使用脚本过滤器来选择其标签是查询中传递的标签子集的文档。对于我的用例(数千个文档,而不是数百万个文档),这工作得非常快 - 几十毫秒。
第一次使用脚本,耗时较长(约1000ms),可能是编译和缓存的原因。但后来的调用速度要快 100 倍。
几点说明: