Запрос Elasticsearch с вложенными наборами - PullRequest
0 голосов
/ 29 марта 2020

Я довольно новичок в Elasticsearch, поэтому, пожалуйста, потерпите меня и дайте мне знать, если мне потребуется предоставить дополнительную информацию. Я унаследовал проект, и мне нужно реализовать новые функции поиска. Структура документа / сопоставления уже существует, но ее можно изменить, если она не поможет мне достичь того, чего я пытаюсь достичь. Я использую Elasticsearch версии 5.6.16.

Компания может предложить ряд услуг. Каждое предложение услуг сгруппировано в набор. Каждый набор composer из 3 категорий;

  • Продукт (ы) (ID 1)
  • Процесс (ы) (ID 3)
  • Материал (и) ) (ID 4)

Структура документа выглядит так:

[{
  "id": 4485,
  "name": "Company A",
  // ...
  "services": {
    "595": {
      "1": [
        95, 97, 91
      ],
      "3": [
        475, 476, 471
      ],
      "4": [
        644, 645, 683
      ]
    },
    "596": {
      "1": [
        91, 89, 76
      ],
      "3": [
        476, 476, 301
      ],
      "4": [
        644, 647, 555
      ]
    },
    "597": {
      "1": [
        92, 93, 89
      ],
      "3": [
        473, 472, 576
      ],
      "4": [
        641, 645, 454
      ]
    },
  }
}]

В приведенном выше примере; 595, 596 и 597 являются идентификаторами, относящимися к набору. 1, 3 и 4 относятся к категориям (упомянутым выше).

Отображение выглядит следующим образом:

[{
  "id": {
    "type": "long"
  },
  "name": {
    "type": "text",
    "fields": {
      "keyword": {
        "type": "keyword",
        "ignore_above": 256
      }
    }
  },
  "services": {
    "properties": {
      // ...
      "595": {
        "properties": {
          "1": {"type": "long"},
          "3": {"type": "long"},
          "4": {"type": "long"}
        }
      },
      "596": {
        "properties": {
          "1": {"type": "long"},
          "3": {"type": "long"},
          "4": {"type": "long"}
        }
      },
      // ...
    }
  },
}]

При поиске компании, которая предоставляет Продукт (ID 1) - поиск из 91 и 95, который вернул бы компанию A, потому что эти идентификаторы находятся в одном наборе. Но если бы я искал 95 и 76, он не вернул бы Компанию А - хотя компания делает оба этих продукта, они не находятся в одном наборе. Эти же правила будут применяться при поиске процессов и материалов или их комбинации.

Я ищу подтверждение того, что текущая структура документа / сопоставления облегчит этот тип поиска.

  • Если это так, учитывая 3 массива идентификаторов (Продукты, Процессы и Материалы), каково JSON, чтобы найти все компании, которые предоставляют эти услуги в одном наборе?
  • Если нет, то как следует документировать / отображать изменить, чтобы разрешить этот поиск?

Спасибо за вашу помощь.

1 Ответ

1 голос
/ 29 марта 2020

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

Вместо этого измените модель данных на что-то вроде ниже. Я также включил образцы документов, возможные запросы, которые вы можете подать, и как может появиться ответ.

Обратите внимание, что просто для простоты я сосредоточусь только на поле services, которое вы упомянули в своем отображении.

Отображение:

PUT my_services_index
{
  "mappings": {
    "properties": {
      "services":{
        "type": "nested",                   <----- Note this
        "properties": {
          "service_key":{
            "type": "keyword"               <----- Note that I have mentioned keyword here. Feel free to use text and keyword if you plan to implement partial + exact search.
          },
          "product_key": {
            "type": "keyword"
          },
          "product_values": {
            "type": "keyword"
          },
          "process_key":{
            "type": "keyword"
          },
          "process_values":{
            "type": "keyword"
          },
          "material_key":{
            "type": "keyword"
          },
          "material_values":{
            "type": "keyword"
          }
        }
      }
    }
  }
}

Обратите внимание, что я использовал вложенный тип данных. Я бы предложил вам go по этой ссылке, чтобы понять, зачем нам это нужно вместо простого object типа.

Образец документа:

POST my_services_index/_doc/1
{
  "services":[
  {
    "service_key": "595",
    "process_key": "1",
    "process_values": ["95", "97", "91"],
    "product_key": "3",
    "product_values": ["475", "476", "471"],
    "material_key": "4",
    "material_values": ["644", "645", "643"]
  },
  {
    "service_key": "596",
    "process_key": "1",
    "process_values": ["91", "89", "75"],
    "product_key": "3",
    "product_values": ["476", "476", "301"],
    "material_key": "4",
    "material_values": ["644", "647", "555"]
  }
    ]
}

Обратите внимание на то, как теперь вы можете управлять своими данными, если они в конечном итоге имеют несколько комбинаций или product_key, process_key and material_key.

То, как вы интерпретируете вышеупомянутый документ, состоит в том, что у вас есть два вложенных документа внутри документа из my_services_index.

Пример запроса:

POST my_services_index/_search
{
  "_source": "services.service_key", 
  "query": {
    "bool": {
      "must": [
        {
          "nested": {                                      <---- Note this
            "path": "services",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "services.service_key": "595"
                    }
                  },
                  {
                    "term": {
                      "services.process_key": "1"
                    }
                  },
                  {
                    "term": {
                      "services.process_values": "95"
                    }
                  }
                ]
              }
            },
            "inner_hits": {}                              <---- Note this
          }
        }
      ]
    }
  }
}

Обратите внимание, что я использовал Вложенный запрос .

Ответ:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.828546,
    "hits" : [                              <---- Note this. Which would return the original document. 
      {
        "_index" : "my_services_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.828546,
        "_source" : {
          "services" : [
            {
              "service_key" : "595",
              "process_key" : "1",
              "process_values" : [
                "95",
                "97",
                "91"
              ],
              "product_key" : "3",
              "product_values" : [
                "475",
                "476",
                "471"
              ],
              "material_key" : "4",
              "material_values" : [
                "644",
                "645",
                "643"
              ]
            },
            {
              "service_key" : "596",
              "process_key" : "1",
              "process_values" : [
                "91",
                "89",
                "75"
              ],
              "product_key" : "3",
              "product_values" : [
                "476",
                "476",
                "301"
              ],
              "material_key" : "4",
              "material_values" : [
                "644",
                "647",
                "555"
              ]
            }
          ]
        },
        "inner_hits" : {                    <--- Note this, which would tell you which inner document has been a hit. 
          "services" : {
            "hits" : {
              "total" : {
                "value" : 1,
                "relation" : "eq"
              },
              "max_score" : 1.828546,
              "hits" : [
                {
                  "_index" : "my_services_index",
                  "_type" : "_doc",
                  "_id" : "1",
                  "_nested" : {
                    "field" : "services",
                    "offset" : 0
                  },
                  "_score" : 1.828546,
                  "_source" : {
                    "service_key" : "595",
                    "process_key" : "1",
                    "process_values" : [
                      "95",
                      "97",
                      "91"
                    ],
                    "product_key" : "3",
                    "product_values" : [
                      "475",
                      "476",
                      "471"
                    ],
                    "material_key" : "4",
                    "material_values" : [
                      "644",
                      "645",
                      "643"
                    ]
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

Обратите внимание, что я использовал тип данных keyword. Пожалуйста, не стесняйтесь использовать тип данных, и каковы будут ваши бизнес-требования для всех областей.

Идея, которую я предоставил, состоит в том, чтобы помочь вам понять модель документа.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...