Подтвердить что ты не робот

Лечить ребенка как поле родителя в эластичном поисковом запросе

Я читаю документы для elasticsearch, и эта [страница] [1] рассказывает о сопоставлении дочернего элемента с родительским типом с помощью _parent.

Если у меня есть дочерние элементы с именем email, прикрепленные к родителям с именем account:

Поля в каждом типе:

account (http://localhost:9200/myapp/account/1)
========
id
name
some_other_info
state

email (http://localhost:9200/myapp/email/1?parent=1)
========
id
email
  • Как я могу искать в поле name поля account и email email при условии, что state of account равен active?

  • Есть ли способ получить все дети (определенного типа или любого типа), которыми владеет родитель?

  • При индексировании дочернего документа можно ли передать родительский объект как свойство объекта в данные JSON, а не являться частью строки запроса?


Попробовав предложение imotov, я придумал этот запрос:

Это выполняется на http://localhost:9200/myapp/account/_search

{
  "query": {
    "bool": {
      "must": [
        {
          "prefix": {
            "name": "a"
          }
        },
        {
          "term": {
            "statuses": "active"
          }
        }
      ],
      "should": [
        {
          "has_child": {
            "type": "emailaddress",
            "query": {
              "prefix": {
                "email": "a"
              }
            }
          }
        }
      ]
    }
  }
}

Проблема заключается в том, что приведенное выше не дает мне никаких учетных записей, в которых совпадает адрес электронной почты.

Эффект, который я хочу, по существу таков:

  • Существует одно окно поиска
  • Пользователи начинают печатать, и окно автозаполнения поиска.
  • Пользовательский запрос проверяется на имя account или любого типа emailaddress.
  • Если accounts были сопоставлены, просто верните их. Если emailaddress совпадают, верните родительскую учетную запись.
  • Ограничение на максимум x (скажем, 10) учитывает каждый поиск.

Итак, мне в основном нужно иметь возможность OR искать между двумя типами и возвращать родительский тип совпадений.


Данные теста:

curl -XPUT http://localhost:9200/test/account/1 -d '{
    "name": "John Smith",
    "statuses": "active"
}'

curl -XPUT http://localhost:9200/test/account/2 -d '{
    "name": "Peter Smith",
    "statuses": "active"
}'

curl -XPUT http://localhost:9200/test/account/3 -d '{
    "name": "Andy Smith",
    "statuses": "active"
}'

//Set up mapping for parent/child relationship

curl -XPUT 'http://localhost:9200/test/email/_mapping' -d '{
    "emails" : {
        "_parent" : {"type" : "account"}
    }
}'

curl -XPUT http://localhost:9200/test/email/1?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/2?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/3?parent=1 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/4?parent=2 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/5?parent=3 -d '{
    "email": "[email protected]"
}'

curl -XPUT http://localhost:9200/test/email/6?parent=3 -d '{
    "email": "[email protected]"
}'

Имотов решение работало для меня. Другим решением, которое я нашел, является запрос account для status = active, затем запустите фильтр bool в результате и используйте has_child для дочернего типа и prefix на name внутри фильтра bool.

4b9b3361

Ответ 1

Важное различие между elasticsearch и реляционными базами данных состоит в том, что elasticsearch не может выполнять объединения. В elasticsearch вы всегда ищете один индекс или объединение индексов. Но в случае отношений родителя/ребенка можно ограничить результаты в родительском индексе, используя запрос для дочернего индекса. Например, этот запрос можно выполнить в типе account.

{
    "bool": {
        "must": [
            { 
                "text" : { "name": "foo" } 
            }, { 
                "term" : { "state": "active" } 
            }, {
                "has_child": {
                    "type": "email",
                    "query": {
                        "text": {"email": "bar" }
                    }
                }
            }
        ]
    }
}

Этот запрос вернет вам только родительский документ (дочерние документы не будут возвращены). Вы можете использовать родительский идентификатор, возвращаемый этим запросом, чтобы найти всех дочерних элементов этого родителя, используя поле _parent, которое по умолчанию сохраняется и индексируется.

{
    "term" : { "_parent": "1" } 
}

Или вы можете ограничить свои результаты только для детей, которые содержат слово bar в поле email:

{
    "bool": {
        "must": [
            { 
                "term" : { "_parent": "1" } 
            }, { 
                "text" : { "email": "bar" } 
            }
        ]
    }
}

Я не думаю, что можно указать родителя в json, если вы не используете _ объемную индексацию.

Таким образом, поиск электронной почты может быть реализован с использованием тестовых данных, представленных в вопросе:

#!/bin/sh
curl -XDELETE 'http://localhost:9200/test' && echo 
curl -XPOST 'http://localhost:9200/test' -d '{
    "settings" : {
        "number_of_shards" : 1,
        "number_of_replicas" : 0
    },
    "mappings" : {
      "account" : {
        "_source" : { "enabled" : true },
        "properties" : {
          "name": { "type": "string", "analyzer": "standard" },
          "statuses": { "type": "string",  "index": "not_analyzed" }
        }
      },
      "email" : {
        "_parent" : {
          "type" : "account"
        },
        "properties" : {
          "email": { "type": "string",  "analyzer": "standard" }
        }
      }
    }
}' && echo

curl -XPUT 'http://localhost:9200/test/account/1' -d '{
    "name": "John Smith",
    "statuses": "active"
}'

curl -XPUT 'http://localhost:9200/test/account/2' -d '{
    "name": "Peter Smith",
    "statuses": "active"
}'

curl -XPUT 'http://localhost:9200/test/account/3' -d '{
    "name": "Andy Smith",
    "statuses": "active"
}'

//Set up mapping for parent/child relationship

curl -XPUT 'http://localhost:9200/test/email/1?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/2?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/3?parent=1' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/4?parent=2' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/5?parent=3' -d '{
    "email": "[email protected]"
}'

curl -XPUT 'http://localhost:9200/test/email/6?parent=3' -d '{
    "email": "[email protected]"
}'

curl -XPOST 'http://localhost:9200/test/_refresh'
echo
curl 'http://localhost:9200/test/account/_search' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "statuses": "active"
          }
        }
      ],
      "should": [
        {
          "prefix": {
            "name": "a"
          }
        },
        {
          "has_child": {
            "type": "email",
            "query": {
              "prefix": {
                "email": "a"
              }
            }
          }
        }
      ],
      "minimum_number_should_match" : 1
    }
  }
}' && echo