Как запросить индексasticsearch с вложенными и не вложенными полями - PullRequest
0 голосов
/ 29 октября 2019

У меня эластичный поисковый индекс со следующим отображением:

PUT /student_detail
{
    "mappings" : {
        "properties" : {
            "id" : { "type" : "long" },
            "name" : { "type" : "text" },
            "email" : { "type" : "text" },
            "age" : { "type" : "text" },
            "status" : { "type" : "text" },
            "tests":{ "type" : "nested" }
        }
    }
}

Данные хранятся в форме ниже:

{
  "id": 123,
  "name": "Schwarb",
  "email": "abc@gmail.com",
  "status": "current",
  "age": 14,
  "tests": [
    {
      "test_id": 587,
      "test_score": 10
    },
    {
      "test_id": 588,
      "test_score": 6
    }
  ]
}

Я хочу иметь возможность запрашивать студентов, где имякак "% warb%" И электронная почта, как "% gmail.com%" И тест с идентификатором 587 имеет оценку> 5 и т. д. Высокий уровень того, что нужно, можно поставить примерно так, как показано ниже, не знаю, какой будет фактический запрос,извинитесь за этот беспорядочный запрос ниже

GET developer_search/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "abc"
          }
        },
        {
          "nested": {
            "path": "tests",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "tests.test_id": IN [587]
                    }
                  },
                   {
                    "term": {
                      "tests.test_score": >= some value
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Запрос должен быть гибким, чтобы мы могли вводить динамические тестовые идентификаторы и соответствующие им фильтры оценок вместе с полями из вложенных полей, таких как возраст, имя, статус

Ответы [ 2 ]

0 голосов
/ 30 октября 2019

Вы должны использовать Ngram Tokenizer , так как поиск по шаблону не должен использоваться из соображений производительности, и я бы не рекомендовал его использовать.

Измените ваше сопоставление на приведенное ниже, где вы можете создать свой собственный Анализатор , который я сделал в приведенном ниже сопоставлении.

Как эластичный поиск (albiet lucene) индексирует утверждениесначала он разбивает оператор или абзац на слова или токены, затем индексирует эти слова в инвертированном индексе для этого конкретного поля. Этот процесс называется Анализ , и он будет применим только к типу данных text.

Так что теперь вы получаете документы, только если эти токены доступны в инвертированном индексе.

По умолчанию будет применяться стандартный анализатор . Я создал свой собственный анализатор и использовал Ngram Tokenizer, который создавал бы намного больше токенов, чем просто слова.

Анализатор по умолчанию для Life is beautiful будет life, is, beautiful.

Однако при использовании Ngrams токены для Life будут lif, ife & life

Mapping:

PUT student_detail
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 3,
          "max_gram": 4,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
    "mappings" : {
        "properties" : {
            "id" : { 
              "type" : "long" 
            },
            "name" : { 
              "type" : "text",
              "analyzer": "my_analyzer",
              "fields": {
                "keyword": {
                  "type": "keyword"
                }
              }
            },
            "email" : { 
              "type" : "text",
              "analyzer": "my_analyzer",
              "fields": {
                "keyword": {
                  "type": "keyword"
                }
              }
            },
            "age" : { 
              "type" : "text"             <--- I am not sure why this is text. Change it to long or int. Would leave this to you
            },
            "status" : { 
              "type" : "text",
              "analyzer": "my_analyzer",
              "fields": {
                "keyword": {
                  "type": "keyword"
                }
              }
            },
            "tests":{ 
              "type" : "nested" 
            }
        }
    }
}

Обратите внимание, что ввыше сопоставления я создал одноуровневое поле в форме ключевого слова для name, email и status, как показано ниже:

"name":{ 
   "type":"text",
   "analyzer":"my_analyzer",
   "fields":{ 
      "keyword":{ 
         "type":"keyword"
      }
   }
}

Теперь ваш запрос может быть простым, как показано ниже.

Запрос:

POST student_detail/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "war"                      <---- Note this. This would even return documents having "Schwarb"
          }
        },
        {
          "match": {
            "email": "gmail"                   <---- Note this
          }
        },
        {
          "nested": {
            "path": "tests",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "tests.test_id": 587
                    }
                  },
                  {
                    "range": {
                      "tests.test_score": {
                        "gte": 5
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Обратите внимание, что для точных совпадений я бы использовал Запросы терминов для ключевых слов полей, в то время как для обычного поиска или LIKEв SQL я бы использовал простые запросы на совпадение на текст поля при условии они используют Ngram Tokenizer.

Также обратите внимание, что для >= и <= вам потребуется использовать Range Query .

Ответ:

{
  "took" : 233,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 3.7260926,
    "hits" : [
      {
        "_index" : "student_detail",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 3.7260926,
        "_source" : {
          "id" : 123,
          "name" : "Schwarb",
          "email" : "abc@gmail.com",
          "status" : "current",
          "age" : 14,
          "tests" : [
            {
              "test_id" : 587,
              "test_score" : 10
            },
            {
              "test_id" : 588,
              "test_score" : 6
            }
          ]
        }
      }
    ]
  }
}

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

Пожалуйста, прочитайте ссылки, которыми я поделился. Важно, чтобы вы поняли концепции. Надеюсь, это поможет!

0 голосов
/ 30 октября 2019

Что-то в этом роде?

GET student_detail/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "name": {
              "value": "*warb*"
            }
          }
        },
        {
          "wildcard": {
            "email": {
              "value": "*gmail.com*"
            }
          }
        },
        {
          "nested": {
            "path": "tests",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "tests.test_id": 587
                    }
                  },
                  {
                    "range": {
                      "tests.test_score": {
                        "gte": 5
                      }
                    }
                  }
                ]
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  }
}

Внутренние хиты - это то, что вы ищете.

...