Руководство по Elasticsearch в Java
1. обзор
В этой статье мы собираемся погрузиться в некоторые ключевые концепции, связанные с полнотекстовыми поисковыми системами, с особым акцентом на Elasticsearch.
Поскольку это статья, ориентированная на Java, мы не собираемся давать подробное пошаговое руководство о том, как настроить Elasticsearch и показывать, как он работает под капотом, вместо этого мы собираемся настроить таргетинг на клиент Java, и как использовать основные функции, такие какindex,delete,get иsearch.
2. Настроить
Чтобы установить Elasticsearch на свой компьютер, обратитесь кofficial setup guide.
Процесс установки довольно прост, просто загрузите пакет zip / tar и запустите файл сценарияelasticsearch (elasticsearch.bat для пользователей Windows).
По умолчанию Elasticsearch прослушивает порт 9200 для ожидающих HTTP-запросов по умолчанию. Мы можем убедиться, что он успешно запущен, открыв URL-адресhttp://localhost:9200/ в вашем любимом браузере:
{
"name" : "GEpcsab",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "z3FfAe6gRMmSmeWBIOihJg",
"version" : {
"number" : "5.6.10",
"build_hash" : "b727a60",
"build_date" : "2018-06-06T15:48:34.860Z",
"build_snapshot" : false,
"lucene_version" : "6.6.1"
},
"tagline" : "You Know, for Search"
}
3. Конфигурация Maven
Теперь, когда у нас есть наш базовый кластер Elasticsearch, давайте перейдем непосредственно к клиенту Java. Прежде всего, нам нужно, чтобы следующийMaven dependency был объявлен в нашем файлеpom.xml:
org.elasticsearch
elasticsearch
5.6.0
Вы всегда можете проверить последние версии, размещенные на Maven Central, по ссылке, указанной ранее.
4. Java API
Прежде чем мы сразу перейдем к тому, как использовать основные функции Java API, нам нужно запустить транспортный клиент:
Client client = new PreBuiltTransportClient(
Settings.builder().put("client.transport.sniff", true)
.put("cluster.name","elasticsearch").build())
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
4.1. Индексирование документов
ФункцияprepareIndex() позволяет сохранить произвольный документ JSON и сделать его доступным для поиска:
@Test
public void givenJsonString_whenJavaObject_thenIndexDocument() {
String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564,"
+"\"fullName\":\"John Doe\"}";
IndexResponse response = client.prepareIndex("people", "Doe")
.setSource(jsonObject, XContentType.JSON).get();
String id = response.getId();
String index = response.getIndex();
String type = response.getType();
long version = response.getVersion();
assertEquals(Result.CREATED, response.getResult());
assertEquals(0, version);
assertEquals("people", index);
assertEquals("Doe", type);
}
При запуске теста обязательно объявите переменнуюpath.home, иначе может возникнуть следующее исключение:
java.lang.IllegalStateException: path.home is not configured
После выполнения команды Maven:mvn clean install -Des.path.home=C:\elastic документ JSON будет сохранен сpeople в качестве индекса иDoe в качестве типа.
Обратите внимание, что можно использоватьany JSON Java library для создания и обработки ваших документов. If you are not familiar with any of these, you can use Elasticsearch helpers to generate your own JSON documents:
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("fullName", "Test")
.field("dateOfBirth", new Date())
.field("age", "10")
.endObject();
IndexResponse response = client.prepareIndex("people", "Doe")
.setSource(builder).get();
assertEquals(Result.CREATED, response.getResult());
4.2. Запрос проиндексированных документов
Теперь, когда у нас есть проиндексированный типизированный документ JSON с возможностью поиска, мы можем продолжить поиск, используя методprepareSearch():
SearchResponse response = client.prepareSearch().execute().actionGet();
List searchHits = Arrays.asList(response.getHits().getHits());
List results = new ArrayList();
searchHits.forEach(
hit -> results.add(JSON.parseObject(hit.getSourceAsString(), Person.class)));
The results returned by the actionGet() method are called Hits, каждыйHit относится к документу JSON, соответствующему поисковому запросу.
В этом случае списокresults содержит все данные, хранящиеся в кластере. Обратите внимание, что в этом примере мы используем библиотекуFastJson для преобразования JSONStrings в объекты Java.
Мы можем улучшить запрос, добавив дополнительные параметры, чтобы настроить запрос с помощью методовQueryBuilders:
SearchResponse response = client.prepareSearch()
.setTypes()
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setPostFilter(QueryBuilders.rangeQuery("age").from(5).to(15))
.execute()
.actionGet();
4.3. Получение и удаление документов
МетодыprepareGet() иprepareDelete() позволяют получить или удалить документ JSON из кластера по его идентификатору:
GetResponse response = client.prepareGet("people","Doe","1").get();
String age = (String) response.getField("age").getValue();
// Process other fields
DeleteResponse response = client.prepareDelete("people", "Doe", "5")
.get();
Синтаксис довольно прост, вам просто нужно указать индекс и значение типа вместе с идентификатором объекта.
5. QueryBuilders Примеры
КлассQueryBuilders предоставляет множество статических методов, используемых в качестве динамических сопоставителей для поиска определенных записей в кластере. Используя методprepareSearch() для поиска определенных документов JSON в кластере, мы можем использовать построители запросов для настройки результатов поиска.
Вот список наиболее частых применений APIQueryBuilders.
МетодmatchAllQuery() возвращает объектQueryBuilder, соответствующий всем документам в кластере:
QueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
rangeQuery() соответствует документам, в которых значение поля находится в определенном диапазоне:
QueryBuilder matchDocumentsWithinRange = QueryBuilders
.rangeQuery("price").from(15).to(100)
Предоставление имени поля - например, fullName, и соответствующее значение - например, John Doe, методmatchQuery() сопоставляет весь документ с этим точным значением поля:
QueryBuilder matchSpecificFieldQuery= QueryBuilders
.matchQuery("fullName", "John Doe");
Мы также можем использовать методmultiMatchQuery() для создания версии запроса на совпадение с несколькими полями:
QueryBuilder matchSpecificFieldQuery= QueryBuilders.matchQuery(
"Text I am looking for", "field_1", "field_2^3", "*_field_wildcard");
We can use the caret symbol (^) to boost specific fields.
В нашем примере дляfield_2 установлено значение повышения, равное трем, что делает его более важным, чем другие поля. Обратите внимание, что можно использовать подстановочные знаки и запросы с регулярными выражениями, но с точки зрения производительности, остерегайтесь потребления памяти и задержки времени ответа при работе с подстановочными знаками, потому что что-то вроде * _apples может оказать огромное влияние на производительность.
Коэффициент важности используется для упорядочивания результирующего набора совпадений, возвращаемых после выполнения методаprepareSearch().
Если вы более знакомы с синтаксисом запросов Lucene, вы можете использоватьsimpleQueryStringQuery() method to customize search queries:
QueryBuilder simpleStringQuery = QueryBuilders
.simpleQueryStringQuery("+John -Doe OR Janette");
Как вы, наверное, догадались,we can use the Lucene’s Query Parser syntax to build simple, yet powerful queries. Вот несколько основных операторов, которые можно использовать вместе с операторамиAND/OR/NOT для построения поисковых запросов:
-
Требуемый оператор (+): требует, чтобы определенный фрагмент текста существовал где-то в полях документа.
-
Оператор запрета (–): исключает все документы, содержащие ключевое слово, объявленное после символа (–).
6. Заключение
В этой быстрой статье мы увидели, как использовать Java API ElasticSearch для выполнения некоторых общих функций, связанных с системами полнотекстового поиска.
Вы можете ознакомиться с примером из этой статьи вGitHub project.