什么是 terms set 查询?
Terms set 查询根据匹配给定字段的精确术语的最少数量返回文档。
terms set 查询与 term 查询有何不同?
Terms set query 和 Terms query 之间的唯一区别是你可以提供必须匹配的最少数量的术语才能检索特定文档。
什么是 minimum_should_match_field 参数?
指向文档的数字(numeric)字段名称,其值应用作要匹配的最少术语数,以便返回文档。
minimum_should_match_script 参数是什么?
一个自定义脚本,用于确定为了返回文档而必须匹配的最少术语数。 如果你必须动态设置匹配所需的术语数,那么它将很有帮助。
示例
让我们首先创建索引:
PUT product
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"tags": {
"type": "keyword"
},
"tags_count": {
"type": "long"
}
}
}
}
让我们索引样本文件:
POST product/_doc/prod1
{
"name":"Iphone 13",
"tags":["apple","iphone","mobile"],
"tags_count":3
}
POST product/_doc/prod2
{
"name":"Iphone 12",
"tags":["apple","iphone"],
"tags_count":2
}
POST product/_doc/prod3
{
"name":"Iphone 11",
"tags":["apple","mobile"],
"tags_count":2
}
使用 minimum_should_match_field 参数查询:
用例 1:下面的查询将返回所有 3 个文档,因为 prod1 的最小术语匹配 (tags_count) 是 3,prod2 是 2,prod3 是 2,查询中传递了总共 3 个术语("apple", "iphone", "mobile")。
POST product/_search
{
"query": {
"terms_set": {
"tags": {
"terms": [ "apple", "iphone", "mobile" ],
"minimum_should_match_field": "tags_count"
}
}
}
}
上述查询的结果是:
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.4010588,
"hits": [
{
"_index": "product",
"_id": "prod1",
"_score": 1.4010588,
"_source": {
"name": "Iphone 13",
"tags": [
"apple",
"iphone",
"mobile"
],
"tags_count": 3
}
},
{
"_index": "product",
"_id": "prod2",
"_score": 0.7876643,
"_source": {
"name": "Iphone 12",
"tags": [
"apple",
"iphone"
],
"tags_count": 2
}
},
{
"_index": "product",
"_id": "prod3",
"_score": 0.7876643,
"_source": {
"name": "Iphone 11",
"tags": [
"apple",
"mobile"
],
"tags_count": 2
}
}
]
}
用例二:下面的查询将只返回一个文档,因为查询中只传递了 2 个术语,仅与 prod3 匹配。 prod1 将不会返回,因为 tags_count 值为 3 并且查询中传递的总术语仅为 2。
POST product/_search
{
"query": {
"terms_set": {
"tags": {
"terms": [ "apple", "mobile" ],
"minimum_should_match_field": "tags_count"
}
}
}
}
上述查询的结果为:
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.5007585,
"hits": [
{
"_index": "product",
"_id": "prod3",
"_score": 0.5007585,
"_source": {
"name": "Iphone 11",
"tags": [
"apple",
"mobile"
],
"tags_count": 2
}
}
]
}
minimum_should_match_script 示例:
现在让我们看看如何使用 minimum should match 的动态值检索相同的索引数据。
在下面的示例中,查询中提供的术语总数的值将作为最小应匹配值传递。 我们将使用 params.num_terms 来计算查询中提供的术语数。 需要匹配的词条数不能超过 params.num_terms,即 terms 字段中提供的词条数。
POST product/_search
{
"query": {
"terms_set": {
"tags": {
"terms": ["apple","iphone"],
"minimum_should_match_script": {
"source": "params.num_terms"
}
}
}
}
}
它将返回 prod1 和 prod2,因为 minimum_should_match 值将设置为 2,因为我们在查询中仅传递了 2 个术语。上述命令的返回值为:
"hits": [
{
"_index": "product",
"_id": "prod2",
"_score": 0.5007585,
"_source": {
"name": "Iphone 12",
"tags": [
"apple",
"iphone"
],
"tags_count": 2
}
},
{
"_index": "product",
"_id": "prod1",
"_score": 0.5007585,
"_source": {
"name": "Iphone 13",
"tags": [
"apple",
"iphone",
"mobile"
],
"tags_count": 3
}
}
]
}
让我们考虑一个场景,你想要考虑 tags_count 的最小值或查询中的术语数; 在这种情况下,以下查询会有所帮助:
POST product/_search
{
"query": {
"terms_set": {
"tags": {
"terms": ["apple","iphone"],
"minimum_should_match_script": {
"source": "Math.min(params.num_terms, doc['tags_count'].value)"
}
}
}
}
}
上述查询的结果为:
"hits": [
{
"_index": "product",
"_id": "prod2",
"_score": 0.61233616,
"_source": {
"name": "Iphone 12",
"tags": [
"apple",
"iphone"
],
"tags_count": 2
}
},
{
"_index": "product",
"_id": "prod1",
"_score": 0.61233616,
"_source": {
"name": "Iphone 13",
"tags": [
"apple",
"iphone",
"mobile"
],
"tags_count": 3
}
}
]
}
Terms set 查询 Elasticsearch Java 客户端
下面的代码将有助于使用 Elasticsearch Java 客户端实现术语集查询。
Using new Java API Client (8.x)
List<String> tags = new ArrayList<String>();
tags.add("apple");
tags.add("iphone");
// Using minimum_should_match_field param
Query query1 = Query.of(q -> q.bool(BoolQuery.of(bq -> bq.must(ts -> ts.termsSet(
TermsSetQuery.of(tq -> tq.field("tags").minimumShouldMatchField("tags_count").terms(tags)))))));
//Using minimum_should_match_script param
Map<String, JsonData> param = new HashMap<String, JsonData>();
Query query1 = Query
.of(q -> q.bool(BoolQuery.of(bq -> bq.must(ts -> ts.termsSet(TermsSetQuery.of(tq -> tq.field("tags")
.minimumShouldMatchScript(sc -> sc.inline(in -> in.lang("painless").source("params.num_terms").params(param)))
.terms(tags)))))));
使用 Java High Level 客户端(已弃用)
Map<String, Object> param = new HashMap<String, Object>();
Script script = new Script(ScriptType.INLINE, "painless", "params.num_terms", param);
List<String> tags = new ArrayList<String>();
tags.add("apple");
tags.add("iphone");
// Using minimum_should_match_field
QueryBuilder query = QueryBuilders.boolQuery()
.must(new TermsSetQueryBuilder("tags", tags).setMinimumShouldMatchField("tags_count"));
// Using minimum_should_match_script
Map<String, Object> param = new HashMap<String, Object>();
Script script = new Script(ScriptType.INLINE, "painless", "params.num_terms", param);
QueryBuilder query = QueryBuilders.boolQuery()
.must(new TermsSetQueryBuilder("tags", tags).setMinimumShouldMatchScript(script));