我的文件包含标签列表:
{ "fields": { "label": [ "foo", "bar", "baz" ], "name": [ "Document One" ], "description" : "A fine first document", "id" : 1 } }, { "fields": { "label": [ "foo", "dog" ], "name": [ "Document Two" ], "description" : "A fine second document", "id" : 2 } }
我有一个术语列表:
[ "foo", "bar", "qux", "zip", "baz"]
我想要一个查询,它将返回在术语列表中包含标签的文档 - 但没有其他术语。
因此,根据上面的列表,查询将返回Document One
,但不 Document Two
(因为它的列表中不包含dog
项条款。
我尝试使用not
terms
过滤器进行查询,如下所示:
POST /documents/_search?size=1000 { "fields": [ "id", "name", "label" ], "filter": { "not": { "filter" : { "bool" : { "must_not": { "terms": { "label": [ "foo", "bar", "qux", "zip", "baz" ] } } } } } } }
但那没用。
如何创建一个查询,在给定术语列表的情况下,该查询将匹配仅包含列表中的术语的文档,而不包含其他术语?换句话说,所有文档都应包含标签列表,这些标签是所提供术语列表的子集。
答案 0 :(得分:2)
我遵循了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
}
我的实际查询需要将脚本过滤器与功能分数查询相结合,这很难弄清楚如何操作,因此我将此处作为示例包含在内。
这样做是使用脚本过滤器来选择其标签是查询中传递的标签子集的文档。对于我的用例(数千个文档,而不是数百万个),这个工作非常快 - 几十毫秒。
第一次使用脚本时,可能需要很长时间(约1000毫秒),这可能是由于编译和缓存造成的。但是后来的调用速度提高了100倍。
几点说明:
答案 1 :(得分:1)
您可以使用脚本过滤器来检查数组术语是否包含文档中标签数组的所有值。我建议你制作一个单独的groovy文件或普通的javascript文件,把它放在config / scripts / folderToYourScript中,并在filter: { script : {script_file: file } }
在脚本文件中,您可以使用循环来检查需求