带可选字段的嵌套文档的 Elasticsearch 搜索文档
Elasticsearch search document with nested document with optional fields
我正在尝试为包含年份和月份的嵌套对象创建查询。它们都是可选的。如果某些字段不存在,我们将它们视为命中。我找到了一个解决方案,但它会导致术语的组合爆炸,所以我正在努力寻找更好的解决方案。
复制步骤:
- 正在使用映射创建索引
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested"
}
}
}
}
- 添加带有嵌套对象的文档
PUT /date-test/_doc/1
{
"name": "Object1",
"datesOfBirth": []
}
PUT /date-test/_doc/2
{
"name": "Object2",
"datesOfBirth": [
{
"year": 1990,
"month": 4
}
]
}
PUT /date-test/_doc/3
{
"name": "Object3",
"datesOfBirth": [
{
"year": 1995,
"month": 2
},
{
"year": 1998,
"month": 4
}
]
}
PUT /date-test/_doc/4
{
"name": "Object4",
"datesOfBirth": [
{
"month": 4
}
]
}
- 此查询在年份范围 1994-1996 和月份范围 1-5 中按预期工作(返回对象 1、3、4):
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [ //match when all fields are absent
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{ "bool": {"must_not": [ //match when year is absent but month exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
]
}},
{ "bool": {"must_not": [ //match when month is absent but year exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } }
]
}}}}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [ //both fields exists and must match to given ranges
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
],
"minimum_should_match": 1
}
}
}
是否有更好的方法来实现该行为?我正在使用 Elasticsearch 7.1。
我也尝试过始终设置字段,但在值缺失的情况下使用 null,并在我定义 null_value: -1 的地方添加年份和月份的映射。然后我可以删除字段缺失组合的部分。
- 使用映射创建索引
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested",
"properties": {
"year": { "type": "integer", "null_value": -1 },
"month": { "type": "integer", "null_value": -1 }
}
}
}
}
}
- 正在创建文档如下:
PUT /date-test/_doc/7
{
"name": "SomeObjectWithoutYear",
"datesOfBirth": [
{
"year": null,
"month": 4
}
]
}
然后我可以这样查询:
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "should": [
{ "match": { "datesOfBirth.year": { "query": -1 } } },
{ "match": { "datesOfBirth.month": { "query": -1 } } },
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
],
"minimum_should_match": 2
}}}}
],
"minimum_should_match": 1
}
}
}
但我想知道这是否是实现该目标的最简洁方法。
我正在尝试为包含年份和月份的嵌套对象创建查询。它们都是可选的。如果某些字段不存在,我们将它们视为命中。我找到了一个解决方案,但它会导致术语的组合爆炸,所以我正在努力寻找更好的解决方案。
复制步骤:
- 正在使用映射创建索引
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested"
}
}
}
}
- 添加带有嵌套对象的文档
PUT /date-test/_doc/1
{
"name": "Object1",
"datesOfBirth": []
}
PUT /date-test/_doc/2
{
"name": "Object2",
"datesOfBirth": [
{
"year": 1990,
"month": 4
}
]
}
PUT /date-test/_doc/3
{
"name": "Object3",
"datesOfBirth": [
{
"year": 1995,
"month": 2
},
{
"year": 1998,
"month": 4
}
]
}
PUT /date-test/_doc/4
{
"name": "Object4",
"datesOfBirth": [
{
"month": 4
}
]
}
- 此查询在年份范围 1994-1996 和月份范围 1-5 中按预期工作(返回对象 1、3、4):
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [ //match when all fields are absent
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{ "bool": {"must_not": [ //match when year is absent but month exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
]
}},
{ "bool": {"must_not": [ //match when month is absent but year exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } }
]
}}}}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [ //both fields exists and must match to given ranges
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
],
"minimum_should_match": 1
}
}
}
是否有更好的方法来实现该行为?我正在使用 Elasticsearch 7.1。
我也尝试过始终设置字段,但在值缺失的情况下使用 null,并在我定义 null_value: -1 的地方添加年份和月份的映射。然后我可以删除字段缺失组合的部分。
- 使用映射创建索引
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested",
"properties": {
"year": { "type": "integer", "null_value": -1 },
"month": { "type": "integer", "null_value": -1 }
}
}
}
}
}
- 正在创建文档如下:
PUT /date-test/_doc/7
{
"name": "SomeObjectWithoutYear",
"datesOfBirth": [
{
"year": null,
"month": 4
}
]
}
然后我可以这样查询:
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "should": [
{ "match": { "datesOfBirth.year": { "query": -1 } } },
{ "match": { "datesOfBirth.month": { "query": -1 } } },
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
],
"minimum_should_match": 2
}}}}
],
"minimum_should_match": 1
}
}
}
但我想知道这是否是实现该目标的最简洁方法。