ElasticSearch嵌套文档查询:匹配学生姓名与ID返回对应文档
关于Elasticsearch嵌套文档匹配的问题
存储的文档
我在Elasticsearch中存储了以下文档:
[ { "class": " Grade 1", "subject": [ "Mathematics", "German", "Geometry", "Arts", "Physical Education" ], "student": [ { "name": "George", "id": "ORT-823FT" }, { "name": "Travis", "id": "ORT-873FT" }, { "name": "Scott", "id": "ORT-883FT" } ] }, { "class": " Grade 2", "subject": [ "Mathematics", "German", "Geometry", "French", "Arts", "Physical Education" ], "student": [ { "name": "Gibbs", "id": "ORT-923DG" }, { "name": "Elizabeth", "id": "ORT-973DG" }, { "name": "Michale", "id": "ORT-983DG" } ] } ]
需求
仅当学生姓名与ID属于同一个学生对象时,返回对应的班级文档。例如:
- 匹配姓名
George且ID为ORT-823FT时,返回第一个Grade 1的文档; - 匹配姓名
Gibbs且ID为ORT-923DG时,返回第二个Grade 2的文档。
初始查询及疑问
我使用了以下查询语句,虽然可以运行,但想知道是否有更优写法:
{ "query": { "bool": { "should": [ { "match": { "student.id": "ORT-823FT" } }, { "match": { "student.name": "George" } } ], "minimum_should_match": 2 } } }
更新内容及问题
我已按照文档说明为student字段添加了"type": "nested"映射,具体映射如下:
{ "student": { "type": "nested", "properties": { "studentResidence": { "properties": { "residenceAddress": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "phoneNumber": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "parentEmail": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }, "studentParentRelationShip": { "properties": { "relationshipType": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "residenceAddress": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }, "comments": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "id": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "validFor": { "properties": { "endDateTime": { "type": "date" }, "startDateTime": { "type": "date" } } } } } }
对应的查询语句为:
{ "query": { "nested": { "path": "student", "query": { "bool": { "must": [ { "match": { "student.id": "ORT-823FT" } }, { "match": { "student.name": "George" } } ] } } } } }
但我仍得到错误的输出,不清楚问题出在哪里,寻求解决方法。
解决方案
问题分析
- 字段路径错误:嵌套查询中已经指定了
path: "student",内部查询的字段应该直接写id和name,而不是student.id和student.name,否则会被解析为student.student.id,无法匹配到正确的字段。 - 字段类型不匹配:
id是类似ORT-823FT的标识符,使用text类型的match查询会对输入内容分词,导致无法精确匹配。应该使用keyword子字段或直接将id设为keyword类型来做精确匹配。
修正后的查询语句
使用keyword子字段进行精确匹配,同时修正字段路径:
{ "query": { "nested": { "path": "student", "query": { "bool": { "must": [ { "term": { "id.keyword": "ORT-823FT" } }, { "term": { "name.keyword": "George" } } ] } } } } }
如果偏好使用match查询,也可以改为:
{ "query": { "nested": { "path": "student", "query": { "bool": { "must": [ { "match": { "id.keyword": "ORT-823FT" } }, { "match": { "name.keyword": "George" } } ] } } } } }
优化映射(可选)
由于id是唯一标识符,不需要分词,可以直接将其类型设为keyword,这样查询时更简洁:
"id": { "type": "keyword", "ignore_above": 256 }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
此时查询语句可简化为:
{ "query": { "nested": { "path": "student", "query": { "bool": { "must": [ { "term": { "id": "ORT-823FT" } }, { "term": { "name.keyword": "George" } } ] } } } } }
内容的提问来源于stack exchange,提问作者User27854
相关产品推荐
相关产品推荐

