Решение с двумя отдельными индексами
Так как эластичный поиск не является реляционной базой данных, вы не сможете получить свои результаты за один запрос. Это строгое ограничение эластичного поиска, но оно также является основной причиной его высокой производительности.
По сути, эластичный поиск скомпилирует ваш запрос в запрос Lucene и выполнит сканирование индексов с использованием запроса Lucene. Не существует механизма, в котором какой-либо параметр в запросе (например, значение поля user_id
) зависит от результата другого запроса (например, найти все значения id
из users
, где имя "Fabien") .
Сначала вам нужно выполнить внешнее соединение:
, сначала получите все документы из индекса users
, имя которого равно Fabien
. Если количество документов не ограничено, вам придется выполнить поиск с прокруткой или использовать search_after
секунду, получить все документы из index navigation
, где user_id
находится в наборе документов, возвращенных из первого запроса, и где удовлетворены другие критерии.
Этот подход может быть медленным, и у вас нет гарантий что при выполнении второго запроса индекс пользователей не обновлялся.
Решение с сопоставлением соединений
На самом деле, если вы используете сопоставление типов соединений , вам не нужно используйте агрегаты для вашего варианта использования.
Обратите внимание, что поле соединения имеет несколько ограничений и не рекомендуется в качестве решения по умолчанию для моделирования отношений один ко многим.
Вот рабочий пример, который должен работать для Ваше требование.
Сопоставление: содержит поле пользователя и навигационное поле, а также поле соединения.
PUT /user_navigation
{
"mappings": {
"properties": {
"cookies": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"join_field": {
"type": "join",
"relations": {
"user": "navigation"
}
}
}
}
}
Добавьте несколько документов тестирования. Два родительских документа имеют name: Fabien
, но только у одного есть двое детей с cookies: http://example.com
. У другого документа есть два потомка с cookies: http://example.com
, но он не назван с Fabien
.
POST user_navigation/_doc/_bulk
{ "index" : { "_index" : "user_navigation", "_id" : "1" } }
{ "name" : "Fabien", "join_field": "user" }
{ "index" : { "_index" : "user_navigation", "_id" : "2" } }
{ "name" : "Fabien", "join_field": "user" }
{ "index" : { "_index" : "user_navigation", "_id" : "3" } }
{ "name" : "Autre", "join_field": "user" }
{ "index" : { "_index" : "user_navigation", "routing": "1" } }
{ "cookies": "http://example.com", "join_field": { "name": "navigation", "parent": "1" }}
{ "index" : { "_index" : "user_navigation", "routing": "1"} }
{ "cookies": "http://example.com", "join_field": { "name": "navigation", "parent": "1" }}
{ "index" : { "_index" : "user_navigation", "routing": "2"} }
{ "cookies": "http://example.com", "join_field": { "name": "navigation", "parent": "2" }}
{ "index" : { "_index" : "user_navigation", "routing": "2"} }
{ "cookies": "other_url", "join_field": { "name": "navigation", "parent": "3" }}
{ "index" : { "_index" : "user_navigation", "routing": "3"} }
{ "cookies": "http://example.com", "join_field": { "name": "navigation", "parent": "3" }}
{ "index" : { "_index" : "user_navigation", "routing": "3"} }
{ "cookies": "http://example.com", "join_field": { "name": "navigation", "parent": "3" }}
В следующем запросе используется запрос has_child , и будет возвращен только документ с name: Fabien
и такой, что у него есть как минимум два дочерних документа с cookies: http://example.com
.
GET user_navigation/_doc/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"name": "Fabien"
}
},
{
"has_child": {
"type": "navigation",
"query": {
"term": {
"cookies": "http://example.com"
}
},
"min_children": 2,
"inner_hits": {}
}
}
]
}
}
}
Ответ будет содержать только документ с идентификатором 1.
"min_children"
Параметр позволяет изменить минимальный количество дочерних документов, которые должны выполнить запрос.
"inner_hits": {}
позволяет получить дочерние документы в ответе.