Elasticsearch嵌套字段排序问题:如何按dateBeginning降序排列研究者的affiliations
嗨,我来帮你理清楚哪里出问题了,以及怎么正确实现你要的需求~
你之前的错误点
错误地在nested查询中匹配根文档的
_id
你第一个查询里,把针对根文档的_id匹配放到了nested.query里面,但nested查询的作用是针对嵌套字段affiliations内部的字段做查询,而_id是属于根文档的字段,根本不在affiliations这个嵌套对象里,所以这个匹配完全不生效,自然拿不到正确的结果。混淆了文档级排序和嵌套数组内部排序
第二个查询里的sort是对整个索引里的文档进行排序,而不是对单个文档内部的affiliations数组元素排序。它会把所有researcher文档按照他们的affiliations日期排序,但这不是你要的“单个研究者的affiliations数组内部排序”。
正确的实现方法
你的需求是:获取_id=3的研究者文档,并让他的affiliations数组按dateBeginning降序排列。我们可以通过inner_hits来实现,这也是官方推荐的处理嵌套字段排序的方式。
方法1:直接匹配根文档+inner_hits排序
这个方法最简单,先匹配到目标根文档,再通过inner_hits取出排序后的嵌套字段:
{ "query": { "term": { "_id": "3" } }, "inner_hits": { "path": "affiliations", "sort": [ { "affiliations.dateBeginning": { "order": "desc" } } ] } }
返回结果里,inner_hits字段会包含按日期降序排列的affiliations条目,而原始_source里的数组还是保持原来的顺序(Elasticsearch不会修改_source的内容)。
方法2:结合bool和nested查询(更灵活)
如果需要对嵌套字段加额外过滤条件,比如只保留加拿大的affiliations,就可以用这种方式:
{ "query": { "bool": { "must": [ { "term": { "_id": "3" } }, { "nested": { "path": "affiliations", "query": { // 这里可以加嵌套字段的过滤条件,比如匹配country "term": { "affiliations.country": "Canada" } }, "inner_hits": { "sort": [ { "affiliations.dateBeginning": { "order": "desc" } } ] } } } ] } } }
方法3:用Elasticsearch SQL实现(适合SQL熟悉者)
既然你更熟悉SQL语法,用ES SQL的UNNEST函数展开嵌套数组,再排序即可:
SELECT firstName, lastName, aff.organisation, aff.team, aff.dateBeginning, aff.country FROM researchers, UNNEST(affiliations) AS aff WHERE _id = '3' ORDER BY aff.dateBeginning DESC
这个查询会把每个affiliation作为单独的一行返回,并且按dateBeginning降序排列。
补充说明
Elasticsearch本身不会修改文档_source里的嵌套数组顺序,如果你需要在_source里直接拿到排序后的数组,只能在应用层面获取数据后自己处理,或者用脚本字段生成排序后的数组,但一般推荐用inner_hits的方式来获取排序后的嵌套内容。
内容的提问来源于stack exchange,提问作者Dan

