3级父子关系:文档具有_parent字段,但has_child查询不返回任何结果

时间:2015-01-12 19:39:03

标签: elasticsearch

我有三种类型的文件:请求,工作和驱动程序。请求和工作之间存在父/子关系,工作和驱动程序之间存在父/子关系。这个查询:

`GET batch-val-weekly-2015-02-v1/driver/_search
 {
   "query": {
     "match_all": {}
    },
    "fields": ["_parent"]
 }`

返回文档列表。父字段存在于每个字段中,并提供相应作业文档的ID。但是这个查询:

'GET batch-val-weekly-2015-02-v1/job/_search
 {
   "query": {
      "has_child": {
        "type": "driver",
        "query": {
          "match_all": {}
        }
      }
    }
  }'

不返回任何命中。我也没有从has_parent查询中获取任何命中。

编辑:Elasticsearch deeper level Parent-child relationship (grandchild)回答了这个问题。请参阅下面的解释。

2 个答案:

答案 0 :(得分:0)

当我取出"driver"类型的属性"driver"时,它似乎工作正常。如果这是一个错误,那么删除它似乎解决了这个问题。更具体地说,首先我创建索引(注意"driver"定义与上面发布的内容的区别):

DELETE /test_index

PUT /test_index
{
   "mappings": {
      "request": {
         "_all": {
            "enabled": false
         },
         "_timestamp": {
            "enabled": true
         }
      },
      "job": {
         "_all": {
            "enabled": false
         },
         "_timestamp": {
            "enabled": true
         },
         "_parent": {
            "type": "request"
         }
      },
      "driver": {
         "_all": {
            "enabled": false
         },
         "_parent": {
            "type": "job"
         },
         "properties": {
            "rules": {
               "type": "nested"
            }
         }
      }
   }
}

添加三个相互关联的文档:

PUT /test_index/_bulk
{"index": {"_index": "test_index", "_type": "request", "_id": 1}}
{}
{"index": {"_index": "test_index", "_type": "job", "_id": 1, "_parent":1}}
{}
{"index": {"_index": "test_index", "_type": "driver", "_id": 1, "_parent":1}}
{}

第一个查询有效:

POST /test_index/driver/_search
{
   "query": {
      "match_all": {}
   },
   "fields": [
      "_parent"
   ]
}
...
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "test_index",
            "_type": "driver",
            "_id": "1",
            "_score": 1,
            "fields": {
               "_parent": "1"
            }
         }
      ]
   }
}

第二个查询有效:

POST /test_index/job/_search
{
   "query": {
      "has_child": {
         "type": "driver",
         "query": {
            "match_all": {}
         }
      }
   }
}
...
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "test_index",
            "_type": "job",
            "_id": "1",
            "_score": 1,
            "_source": {}
         }
      ]
   }
}

以下是我使用的代码:

http://sense.qbox.io/gist/602af489fbfb6595c65cd27cff7a1926642ea205

答案 1 :(得分:0)

事实证明,has_parent和has_child查询有两代以上的问题。那是因为这些查询依赖于父和子在同一个分片上。默认情况下,使用其ID将文档路由到分片(有关此here的更多信息)。建立父子关系时,子文档将根据其 ID进行路由,以确保它们最终位于同一个分片上。

因此,如果您有三代人 - 父母,子女,孙子女 - 那么孩子们就会使用父母的身份证进行路由,而孙子女则使用孩子的身份证进行路由。但孩子们没有使用他们自己的身份证路由,他们使用父母的身份证路由;所以孙子们最终没有找到正确的分片,并且has_parent / has_child查询找不到它们。

解决这个问题的方法是根据父母的ID路由孙子孙女。这是可配置的,请参阅Elasticsearch路由文档here。您还可以通过Java API设置自定义路由。这就是我所做的,它解决了这个问题。

查看此stackoverflow答案以获取更多信息:Elasticsearch deeper level Parent-child relationship (grandchild)