关于inner_hits
关于inner_hits
本文将从以下几个方面回答有关inner_hits的一些问题:
- 什么是inner_hits
- 为什么要有inner_hits
- 如何使用inner_hits
问题1,什么是inner_hits?
inner_hits是ElasticSearch进行nested,has_parent,has_child搜索时的一个选项,用来标记命中文档位置的。以官方文档中的例子为例。
PUT blog
{
"mappings": {
"properties": {
"comments": {
"type": "nested"
}
}
}
}
PUT blog/_doc/1?refresh
{
"title": "Test title",
"comments": [
{
"author": "kimchy",
"number": 1
},
{
"author": "nik9000",
"number": 2
}
]
}
索引”blog“有一个类型为”nested“的字段”comments“,我们写入了一个文档,其中包含了2个”comments“。下面我们对文档进行搜索,我们先不添加”inner_hits“看一下结果是怎么样:
POST test/_search
{
"query": {
"nested": {
"path": "comments",
"query": {
"match": {
"comments.number": "2"
}
}
}
}
}
.....
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"title" : "Test title",
"comments" : [
{
"author" : "kimchy",
"number" : 1
},
{
"author" : "nik9000",
"number" : 2
}
]
}
}
]
可以看到,这个结果和正常搜索没有太多区别。
现在我们在搜索时加入”inner_hits“看一下效果,为了简单起见,”inner_hits“不使用任何选项。
POST test/_search
{
"query": {
"nested": {
"path": "comments",
"query": {
"match": {
"comments.number": 2
}
},
"inner_hits": {
}
}
}
}
我们可以看到结果比刚才多了一个”inner_hits“块:
"inner_hits" : {
"comments" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "comments",
"offset" : 1
},
"_score" : 1.0,
"_source" : {
"author" : "nik9000",
"number" : 2
}
}
]
}
}
}
可以看到,”inner_hits“中包含了关于此处文档的一些匹配信息,其中比较重要的有两个:
”nested“,告诉我们此次命中是文档中的那个nested字段,我们的例子里只有一个”nested“类型的字段,而实际上一个索引中,默认最多可以有50个”nested“类型的字段,这个值由索引的配置项”index.mapping.nested_fields.limit“控制。
”_source“,告诉我们当前命中的是哪个文档。我们的例子里,查询的条件是”number=2“,因此在 ”_source“部分返回了对应的那个文档。“inner_hits”有一个选项“_source”,默认值是true,如果将其置为false可以在返回结果中不显示”_source“的内容。
问题2,为什么要使用inner_hits?
在ElasticSearch中,nested对象是以独立的隐藏文档的方式进行存储的,以上面的例子为例,id为1的文档,有2个comments类型的nested对象,最终存储在ES中的其实是三个文档。而relation类型的对象,父子文档的结构可以完全不同,却是存储在同一个索引中。在进行nested search或者has_child,has_parent search的时候我们可能需要知道,我们的搜索到底是匹配了哪些更细粒度的文档。因此需要inner_hits。
问题3,怎样使用inner_hits
最简单的用法,如上文例子中使用的一样。直接加入一个空的“inner_hits”块即可。除此之外还有一些更细粒度的控制选项:
"from": 指定从文档内部对象array的某个位置开始显示inner_hits。比如说如果from指定为2,那么位置在0和1的文档即使在搜索中被匹配到了,也不会显示在inner_hits里。
"size": 最多显示inner_hits的文档数。
"sorted": 返回inner_hits 对象的排序字段。
"name": 当存在有多个nested字段在搜索中被涉及到时,指定其中某个字段作为inner_hits的显示字段。
更多可参考官方文档的内容
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-request-inner-hits.html
小结
由于nested search,has_parent search,has_child search的文档对象存储方式,在进行相关搜索时,会涉及到主文档之外的其他文档,我们需要一种手段来指出命中的原因。inner_hits应运而生,它可以支持命中文档在多个文档组成的array中的位置,以及具体是哪个nested对象被命中了。总而言之,这是一种帮助我们理解搜索结果的方式或者手段。