Полнотекстовый поиск с Solr

Полнотекстовый поиск с Solr

1. обзор

В этой статье мы рассмотрим фундаментальную концепцию поисковой системыApache Solr - полнотекстовый поиск.

The Apache Solr is an open source framework, designed to deal with millions of documents. Мы рассмотрим его основные возможности на примерах с использованием библиотеки Java -SolrJ.

2. Конфигурация Maven

Учитывая тот факт, что Solr является открытым исходным кодом - мы можем просто скачать двоичный файл и запустить сервер отдельно от нашего приложения.

Чтобы общаться с сервером, мы определим зависимость Maven для клиента SolrJ:


    org.apache.solr
    solr-solrj
    6.4.2

Вы можете найти последнюю зависимостьhere.

3. Индексирование данных

Чтобы индексировать и искать данные, нам нужно создатьcore; мы создадим один с именемitem для индексации наших данных.

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

There are many different ways we can index data. Мы можем использовать обработчики импорта данных для импорта данных непосредственно из реляционных баз данных, загрузки данных с помощью Solr Cell с помощью Apache Tika или загрузки данных XML / XSLT, JSON и CSV с помощью обработчиков индексов.

3.1. Индексирование документа Solr

Мы можем индексировать данные вcore, создавSolrInputDocument. Сначала нам нужно заполнить документ нашими данными, а затем вызвать API SolrJ только для индексации документа:

SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", id);
doc.addField("description", description);
doc.addField("category", category);
doc.addField("price", price);
solrClient.add(doc);
solrClient.commit();

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

3.2. Индексирование компонентов

SolrJ предоставляет API для индексации Java-бинов. Чтобы индексировать bean-компонент, нам нужно аннотировать его аннотациями@Field:

public class Item {

    @Field
    private String id;

    @Field
    private String description;

    @Field
    private String category;

    @Field
    private float price;
}

Как только у нас будет бин, индексирование будет простым:

solrClient.addBean(item);
solrClient.commit();

4. Запросы Solr

Поиск - самая мощная возможность Solr. Как только у нас есть документы, проиндексированные в нашем хранилище, мы можем искать ключевые слова, фразы, диапазоны дат и т. Д. Результаты сортируются по релевантности (баллам).

4.1. Основные запросы

Сервер предоставляет API для поисковых операций. Мы можем вызвать обработчики запросов/select или/query.

Давайте выполним простой поиск:

SolrQuery query = new SolrQuery();
query.setQuery("brand1");
query.setStart(0);
query.setRows(10);

QueryResponse response = solrClient.query(query);
List items = response.getBeans(Item.class);

SolrJ будет внутренне использовать основной параметр запросаq в своем запросе к серверу. Количество возвращаемых записей будет 10, индексируется с нуля, еслиstart иrows не указаны.

Приведенный выше поисковый запрос будет искать любые документы, содержащие полное слово“brand1” в любом из его индексированных полей. Обратите внимание, чтоsimple searches are not case sensitive.

Let’s look at another example. Мы хотим найти любое слово, содержащее“rand”, которое начинается с любого количества символов и заканчивается только одним символом. В нашем запросе мы можем использовать подстановочные знаки* и?:

query.setQuery("*rand?");

Запросы Solr также поддерживают логические операторы, как в SQL:

query.setQuery("brand1 AND (Washing OR Refrigerator)");

Все логические операторы должны быть заглавными; парсером запросов поддерживаютсяAND,OR, NOT,+ и -.

Более того, если мы хотим искать по определенным полям, а не по всем проиндексированным полям, мы можем указать их в запросе:

query.setQuery("description:Brand* AND category:*Washing*");

4.2. Фразовые запросы

До этого момента наш код искал ключевые слова в проиндексированных полях. Мы также можем выполнять поиск по фразам в индексированных полях:

query.setQuery("Washing Machine");

Когда у нас есть фраза вроде «Washing Machine», стандартный синтаксический анализатор запросов Solr анализирует ее до «Washing OR Machine». Чтобы найти целую фразу, мы можем добавить выражение только в двойные кавычки:

query.setQuery("\"Washing Machine\"");

We can use proximity search to find words within specific distances. Если мы хотим найти слова, которые разделены как минимум двумя словами, мы можем использовать следующий запрос:

query.setQuery("\"Washing equipment\"~2");

4.3. Запросы диапазона

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

Допустим, мы хотим найти товары, цена которых колеблется от 100 до 300:

query.setQuery("price:[100 TO 300]");

Запрос выше найдет все элементы, цена которых составляет от 100 до 300 включительно. Мы можем использовать «}» и «\{», чтобы исключить конечные точки:

query.setQuery("price:{100 TO 300]");

4.4. Фильтровать запросы

Фильтр запросов может использоваться для ограничения расширенного набора результатов, которые могут быть возвращены. Фильтр запроса не влияет на оценку:

SolrQuery query = new SolrQuery();
query.setQuery("price:[100 TO 300]");
query.addFilterQuery("description:Brand1","category:Home Appliances");

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

Faceting помогает упорядочить результаты поиска по группам. Мы можем фасетировать поля, запросы или диапазоны.

5.1. Полевая огранка

Например, мы хотим получить агрегированное количество категорий в результате поиска. Мы можем добавить в наш запрос полеcategory:

query.addFacetField("category");

QueryResponse response = solrClient.query(query);
List facetResults = response.getFacetField("category").getValues();

facetResults будет содержать количество каждой категории результатов.

5.2. Query Faceting

Фасетирование запроса очень полезно, когда мы хотим вернуть количество подзапросов:

query.addFacetQuery("Washing OR Refrigerator");
query.addFacetQuery("Brand2");

QueryResponse response = solrClient.query(query);
Map facetQueryMap = response.getFacetQuery();

В результатеfacetQueryMap будет иметь количество фасетных запросов.

5.3. Диапазон огранки

Диапазон гранения используется для получения значений диапазона в результатах поиска. Следующий запрос вернет счетчики ценовых диапазонов от 100 до 251 с интервалом 25:

query.addNumericRangeFacet("price", 100, 275, 25);

QueryResponse response = solrClient.query(query);
List rangeFacets =  response.getFacetRanges().get(0).getCounts();

Помимо числовых диапазонов, Solr также поддерживает диапазоны дат, интервал и фасет.

6. Выделение хита

Мы можем захотеть, чтобы ключевые слова в нашем поисковом запросе были выделены в результатах. Это будет очень полезно, чтобы получить лучшее представление о результатах. Давайте проиндексируем некоторые документы и определим ключевые слова, которые нужно выделить:

itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f);
itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f);
itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f);
itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f);

SolrQuery query = new SolrQuery();
query.setQuery("Appliances");
query.setHighlight(true);
query.addHighlightField("category");
QueryResponse response = solrClient.query(query);

Map>> hitHighlightedMap = response.getHighlighting();
Map> highlightedFieldMap = hitHighlightedMap.get("hm0001");
List highlightedList = highlightedFieldMap.get("category");
String highLightedText = highlightedList.get(0);

Мы получимhighLightedText как“Home <em>Appliances</em>”. Обратите внимание, что ключевое слово поискаAppliances помечено тегом<em>. Тег выделения по умолчанию, используемый Solr, -<em>, но мы можем изменить это, установив тегиpre иpost:

query.setHighlightSimplePre("");
query.setHighlightSimplePost("");

7. Предложения по поиску

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

7.1. Проверка орфографии

Стандартный обработчик поиска не включает компонент проверки орфографии; это должно быть настроено вручную. Есть три способа сделать это. Вы можете найти детали конфигурации в официальномwiki page. В нашем примере мы будем использоватьIndexBasedSpellChecker, который использует индексированные данные для проверки орфографии ключевых слов.

Давайте найдем ключевое слово с орфографической ошибкой:

query.setQuery("hme");
query.set("spellcheck", "on");
QueryResponse response = solrClient.query(query);

SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse();
Suggestion suggestion = spellCheckResponse.getSuggestions().get(0);
List alternatives = suggestion.getAlternatives();
String alternative = alternatives.get(0);

Ожидаемая альтернатива нашему ключевому слову“hme” должна быть“home”, поскольку наш индекс содержит термин“home”.. Обратите внимание, чтоspellcheck необходимо активировать перед выполнением поиска.

7.2. Автоматическое предложение условий

Мы можем получить предложения по неполным ключевым словам, чтобы помочь с поиском. Компонент подсказки Solr должен быть настроен вручную. Вы можете найти детали конфигурации в его официальномwiki page.

Мы настроили обработчик запросов с именем/suggest для обработки предложений. Получим предложения по ключевому слову“Hom”:

SolrQuery query = new SolrQuery();
query.setRequestHandler("/suggest");
query.set("suggest", "true");
query.set("suggest.build", "true");
query.set("suggest.dictionary", "mySuggester");
query.set("suggest.q", "Hom");
QueryResponse response = solrClient.query(query);

SuggesterResponse suggesterResponse = response.getSuggesterResponse();
Map> suggestedTerms = suggesterResponse.getSuggestedTerms();
List suggestions = suggestedTerms.get("mySuggester");

Списокsuggestions должен содержать все слова и фразы. Обратите внимание, что в нашей конфигурации мы настроили суггестера с именемmySuggester.

8. Заключение

Эта статья представляет собой краткое введение в возможности поисковой системы и особенности Solr.

Мы затронули многие функции, но они, конечно, лишь поверхностно рассказывают о том, что мы можем сделать с помощью продвинутого и зрелого поискового сервера, такого как Solr.

Используемые здесь примеры, как всегда, доступныover on GitHub.