Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parent Child Relation In Elastic Search 7.5

I am new to "Elastic Search" and currently trying to understand how does ES maintain "Parent-Child" relationship. I started with the following article:

https://www.elastic.co/blog/managing-relations-inside-elasticsearch

But the article is based on old version of ES and I am currently using ES 7.5 which states that:

The _parent field has been removed in favour of the join field.

Now I am currently following this article:

https://www.elastic.co/guide/en/elasticsearch/reference/7.5/parent-join.html

However, I am not able to get the desired result.

I have a scenario in which i have two indices "Person" and "Home". Each "Person" can have multiple "Home" which is basically a one-to-many relation. Problem is when I query to fetch all homes whose parent is "XYZ" person the answer is null.

Below are my indexes structure and search query:

Person Index:

Request URL: http://hostname/person

{
    "mappings": {
        "properties": {
            "name": {
                "type": "text"
            },
            "person_home": {
                "type": "join",
                "relations": {
                    "person": "home"
                }
            }
        }
    }
}

Home Index:

Request URL: http://hostname/home

{
    "mappings": {
        "properties": {
            "state": {
                "type": "text"
            },
            "person_home": {
                "type": "join",
                "relations": {
                    "person": "home"
                }
            }
        }
    }
}

Adding data in person Index

Request URL: http://hostname/person/_doc/1

{
    "name": "shujaat",
    "person_home": {
        "name": "person"
    }
}

Adding data in home index

Request URL: http://hostname/home/_doc/2?routing=1&refresh

{
    "state": "ontario",
    "person_home": {
        "name": "home",
        "parent": "1"
    }
}

Query to fetch data: (To fetch all the records who parent is person id "1")

Request URL: http://hostname/person/_search

   {
    "query": {
        "has_parent": {
            "parent_type": "person",
            "query": {
                "match": {
                    "name": "shujaat"
                }
            }
        }
    }
}

OR

{
    "query": {
        "has_parent": {
            "parent_type": "person",
            "query": {
                "match": {
                    "_id": "1"
                }
            }
        }
    }
}

Response:

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 0,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    }
}

I am unable to understand what I am missing here or what is wrong with the above mentioned query as it not returning any data.

like image 350
shujaat siddiqui Avatar asked Mar 02 '23 21:03

shujaat siddiqui


1 Answers

You should put the parent and child documents in the same index:

The join datatype is a special field that creates parent/child relation within documents of the same index.

So the mapping would look like the following:

PUT http://hostname/person_home
{
    "mappings": {
        "properties": {
            "name": {
                "type": "text"
            },
            "state": {
                "type": "text"
            },
            "person_home": {
                "type": "join",
                "relations": {
                    "person": "home"
                }
            }
        }
    }
}

Notice that it has both fields from your original person and home indexes.

The rest of your code should work just fine. Try inserting the person and home documents into the same index person_home and use the queries as you posted in the question.

What if person and home objects have overlapping field names?

Let's say, both object types have got field name but we want to index and query them separately. In this case we can come up with a mapping like this:

PUT http://hostname/person_home
{
    "mappings": {
        "properties": {
            "person": {
                "properties": {
                    "name": {
                        "type": "text"
                    }
                }
            },
            "home": {
                "properties": {
                    "name": {
                        "type": "keyword"
                    },
                    "state": {
                        "type": "text"
                    }
                }
            },
            "person_home": {
                "type": "join",
                "relations": {
                    "person": "home"
                }
            }
        }
    }
}

Now, we should change the structure of the objects themselves:

PUT http://hostname/person_home/_doc/1
{
    "name": "shujaat",
    "person_home": {
        "name": "person"
    }
}

PUT http://hostname/person_home/_doc/2?routing=1&refresh
{
    "home": {
        "name": "primary",
        "state": "ontario"
    },
    "person_home": {
        "name": "home",
        "parent": "1"
    }
}

If you have to migrate old data from the two old indexes into a new merged one, reindex API may be of use.

like image 164
Nikolay Vasiliev Avatar answered May 05 '23 09:05

Nikolay Vasiliev