Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get mutiple field data from both parent and child in a single elasticsearch query

Is it possible to get field data from both parent and child in a single elasticsearch query? Essentially what I am trying to capture the data for the multiple parent fields and multiple child fields in a single iteration with filtering. I tried various methods of binding the information into a single query but not able to figure out a way from it. Here is how my mapping looks like :-

parent:

_id_parent : values {1}
_source: {_date (20160316), _time (20160316010000), _id_source (test), _year (2016), _month (1)}

child:

_id_child : values {1}
_source: {_id_child (1), _id_parent (1), _child_question (q1), _child_answer (This needs to be done.)}

Expected Output (something similar to below):

    (PARENT)
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [ {
          "_index" : "index",
          "_type" : "parent",
          "_id" : "1",
          "_score" : 1.0,
          "_source":{_id_parent":"1","_id_source":"test","_date":"20160316","_time":"20160316010000","_year":2016,"_month":"1"}
        } ]
      }
        (CHILD)
          "hits" : {
            "total" : 1,
            "max_score" : 1.0,
            "hits" : [ {
              "_index" : "index",
              "_type" : "child",
              "_id" : "1",
              "_score" : 1.0,
              "_source":{"_id_child":"1", "_child_question":"q1","_child_answer":"This needs to be done."}
            } ]
          }

Links:

http://rore.im/posts/elasticsearch-joins/

https://github.com/elastic/elasticsearch/issues/761

https://www.elastic.co/guide/en/elasticsearch/guide/current/children-agg.html

    curl -XGET "$ELASTICSEARCH_ENDPOINT/index/parent/_search?pretty=true" -d "
    {
        "query": {
            "match": {
                "_id_parent": "1"
                }
            },
            "size" : 10,
            "aggs": {
                "_id_parent": {
                    "terms": {
                        "field":"_id_parent",
                        "field":"_id_source",
                        "field":"_date",
                        "field":"_time",
                        "field":"_year",
                        "field":"_month",
                        },
                    "aggs": {
                        "child": {
                            "children": {
                                "type": "child"
                                },
                            "aggs": {
                                "child": {
                                    "terms": {
                                        "field": "child._id_child",
                                        "field": "child._child_question",
                                        "field": "child._child_answer",
                                }
                            }
                        }
                    }
                }
            }
        }
    }"
like image 806
Kausty Avatar asked Mar 18 '16 21:03

Kausty


Video Answer


3 Answers

This sounds like a job for inner hits. This feature allows the you to get at the hits that made a has_child or has_parent match.

In your case you'd make a query against the parent, with a trivial has_child (ie match_all) or vice versa, for example something like

{
    "query" : {
        "has_child" : {
            "type" : "child",
            "query" : {
                "match_all": {}
            },
            "inner_hits" : {} 
        }
    }
}
like image 111
Frederick Cheung Avatar answered Oct 04 '22 02:10

Frederick Cheung


I have made some assumptions... let me know if they are correct

  1. You want a document from the parent mapping which has a document id = 1
  2. You also want all the child documents which have parent_id = 1
  3. You are passing this parent_id from your code to elasticsearch.
  4. You are not asking elasticsearch to filter through multiple parent documents. Before you hit elasticsearch, you already know you want parent document with id = 1

If this is the case, you can create two separate queries

First query would be "get parent doc with id = 1"
Second query would be "get all child docs with parent_id = 1"

And you can use the Elasticsearch's "multisearch API" to send both these requests to elasticsearch in one network call

MultiSearch API

like image 37
abhaybhatia Avatar answered Oct 04 '22 02:10

abhaybhatia


You can use the below example to search from both parent and child index. Hopefully, this will help you.

    GET indexname/_search
    {
      "query": {
      "bool": {
      "must": [
        {
          "bool": {
            "must": [
              {
                "term": {
                  "parentField": {
                    "value": "valuetosearch"
                  }
                }
              }
            ]
          }
        },
        {
          "has_child": {
            "type": "childindex",
            "query": {
               "range" : {
                  "childindexField" : {
                      "lte": "value"
                  }
               }
            }
          }
        }
      ]
      }
    }
   }
like image 38
VIVEK KUMAR Avatar answered Oct 04 '22 03:10

VIVEK KUMAR