Могу ли я объединить подстановочный и полнотекстовый поиск в Elasticsearch? - PullRequest
2 голосов
/ 05 марта 2020

Например, у меня есть данные некоторых названий в Elasticsearch, например,
gamexxx_nightmare,
gamexxx_little_guy

Затем я ввожу
game => искать gamexxx_nightmare и gamexxx_little_guy
little guy => поиск gamexxx_little_guy?

сначала я думаю, что я буду использовать подстановочный знак, чтобы сделать game совпадение gamexxx, во-вторых, это полнотекстовый поиск? Как объединить их в один DSL ??

Ответы [ 2 ]

2 голосов
/ 05 марта 2020

Хотя ответ Джасприта верен, но не объединяет оба требования в одном DSL запроса, как было задано OP в его вопросе Как объединить их в одном DSL ?? .

Это улучшение решения Jaspreet, так как я также не использую подстановочный знак и даже избегаю анализатора n-грамм, который слишком дорогой (увеличивает размер индекса) и требует повторной индексации при изменении требований.

Один поиск Запрос для объединения обоих требований может быть выполнен следующим образом:

Отображение индекса

{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "tokenizer": "standard",
                    "char_filter": [
                        "replace_underscore" -->note this
                    ]
                }
            },
            "char_filter": {
                "replace_underscore": {
                    "type": "mapping",
                    "mappings": [
                        "_ => \\u0020"
                    ]
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer" : "my_analyzer"
            }
        }
    }
}

Индексирование ваших образцов документов

{
   "title" : "gamexxx_little_guy"
}

And

{
   "title" : "gamexxx_nightmare"
}

Один поисковый запрос

{
    "query": {
        "bool": {
            "must": [ --> note this
                {
                    "bool": {
                        "must": [
                            {
                                "prefix": {
                                    "title": {
                                        "value": "game"
                                    }
                                }
                            }
                        ]
                    }
                },
                {
                    "bool": {
                        "must": [
                            {
                                "match": {
                                    "title": {
                                        "query": "little guy"
                                    }
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

Результат

 {
        "_index": "so-46873023",
        "_type": "_doc",
        "_id": "2",
        "_score": 2.2814486,
        "_source": {
           "title": "gamexxx_little_guy"
        }
     }

Важные моменты:

  1. Первая часть запроса - это prefix запрос, который будет соответствовать game в обоих документах. (Это позволит избежать дорогостоящих регулярных выражений).
  2. Во второй части разрешен полнотекстовый поиск, для этого я использовал специальный анализатор, который заменяет _ пробелами, поэтому вам не нужно дорого ( n-грамм в индексе) и простой запрос на совпадение получат результаты.
  3. Выше запроса возвращает результат, соответствующий обоим критериям, вы можете изменить высокоуровневое условие bool на should с must если, Вы хотите вернуть соответствие любым критериям.
1 голос
/ 05 марта 2020

NGrams имеют лучшую производительность, чем подстановочные знаки. Для подстановочных знаков все документы должны быть отсканированы, чтобы увидеть, какие из них соответствуют шаблону Нграммы разбивают текст на маленькие жетоны. Бывшие быстрые лисы будут храниться как [Qui, ui c, ick, Fox, oxe, xes] в зависимости от min_gram и размера max_gram.

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 3,
          "max_gram": 3,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text":{
        "type": "text",
        "analyzer": "my_analyzer"
      }
    }
  }
}

Запрос

GET my_index/_search
{
  "query": {
    "match": {
      "text": "little guy"
    }
  }
}

Если вы хотите go только с подстановочными знаками, тогда вы можете искать по строке not_analyzed. Это будет обрабатывать пробелы между словами

"wildcard": {
      "text.keyword": {
        "value": "*gamexxx*"
      }
}
...