Теперь, когда мы рассмотрели нечеткий поиск, пришло время взглянуть на поиск по близости, который в некоторой степени связан с ним. В предыдущей лекции мы рассматривали поиск по фразе, при котором поисковый запрос заключен в кавычки, а термины должны быть расположены в правильном порядке. При поиске по близости порядок терминов может быть другим или они могут находиться дальше друг от друга, чем в поисковом запросе.
Это полезно, если вы хотите не только убедиться, что термины существуют в поле, но и что они появляются рядом друг с другом, т.е. в одном контексте. Если нечеткий запрос позволяет указать максимальное расстояние редактирования для символов, то поиск по близости позволяет указать максимальное расстояние редактирования слов или терминов в пределах фразы.
Я повторю поисковый запрос из статьи, где я обсуждал фразовые запросы, и вот он перед тем, как превратить его в запрос для бесконтактного поиска.
1 | GET /ecommerce/product/_search?q=name: "pasta spaghetti" |
Обратите внимание, что в запросе используется поиск по строке запроса для фразы pasta spaghetti. Помните, что по умолчанию соответствующие документы должны содержать слова или термины в поисковом запросе именно в таком порядке. Добавив тильду (~) и натуральное число, я могу определить, насколько разным может быть порядок или расстояние между двумя словами в этом запросе. В данном случае я добавлю приближение к двум.
1 | GET /ecommerce/product/_search?q=name: "pasta spaghetti"~2 |
Как видите, синтаксис для добавления близости к поиску точно такой же, как и при добавлении нечеткости к поиску в строке запроса. Единственное отличие заключается в том, что этот поисковый запрос содержит кавычки, что делает его поиском по фразе.
Я добавил в индекс еще один документ, чтобы проиллюстрировать, как это работает, поэтому давайте просто выполним этот запрос. Посмотрев на результаты, вы увидите, что в одном из совпадений есть имя, в котором слова pasta и spaghetti являются обратными по отношению к запросу. Если бы я не добавил к фразе запроса близость двух или более, то этот документ не был бы найден. Однако вы можете задаться вопросом, почему близости в одну единицу недостаточно. Ответ на этот вопрос связан с тем, как рассчитывается расстояние редактирования. Рассмотрим документ с названием Pasta - Spaghetti, который содержит два термина. Вы можете подумать, что близости в один термин будет достаточно, потому что для перемещения спагетти на первую позицию требуется всего одна правка. Однако это не так, потому что сначала термин "спагетти" должен быть перемещен на первую позицию, после чего термин "паста" должен быть перемещен на вторую позицию. Таким образом, с внутренней точки зрения, это фактически считается двумя правками. Поэтому иногда бывает сложно понять, почему та или иная фраза не совпадает.
Обратите внимание, что в описании продукта, который я добавил, написано "Спагетти и макароны - это здорово!". Между спагетти и макаронами есть "и", поэтому я просто хочу показать вам, что, используя поиск по близости, я все равно могу найти это описание с помощью поиска по фразе. Я собираюсь искать в поле описания фразу "спагетти с макаронами" с приближением к единице.
1 | GET /ecommerce/product/_search?q=description: "spaghetti pasta"~1 |
Как вы можете видеть в результатах, документ все еще совпадает из-за близости, которую я указал. Следует отметить, что чем ближе текст в поле к исходному порядку, указанному в строке запроса, тем более релевантным считается этот документ. Также обратите внимание, что можно указать очень высокое значение близости; это не исключит документы, в которых два термина не находятся рядом друг с другом, но даст более высокий балл документам, в которых термины находятся рядом друг с другом. Таким образом, если вы хотите увеличить количество документов, в которых термины находятся рядом друг с другом, но не хотите исключать документы, в которых этого нет, то вам подойдет этот способ.
Теперь, когда я показал вам, как выполнять поиск по близости с помощью строкового запроса, я покажу вам, как выполнить то же самое с помощью запроса DSL.
1 2 3 4 5 6 7 8 9 10 11 | GET /ecommerce/product/_search { "query": { "match_phrase": { "name": { "query": "pasta spaghetti", "slop": 2 } } } } |
Ключ name соответствует полю, по которому будет производиться поиск. Свойство slop используется при выполнении поиска по близости с помощью запроса DSL.
Этот запрос эквивалентен предыдущему запросу с близостью два, и если мы проверим результаты, то увидим, что они одинаковы.
Вот и все! Вот как выполнять поиск по близости в Elasticsearch.