предисловие
ПреамбулаМы упомянули API-интерфейсы Rest для Elastic Search для управления индексами. Фактически Rest Api Elastic Search предоставляет все рабочие интерфейсы. В языках программирования можно напрямую использовать Rest Api для вызова всех функций Elastic Search, но это очень неудобно и интуитивно понятно, поэтому Elastic Search официально предоставляет интерфейсы Api для многих языков. Официально предоставленные интерфейсы языков программирования включают:
- Java
- JavaScript
- Groovy
- PHP
- .NET
- Perl
- Python
- Ruby
В то же время сообщество программистов также предоставляет API для большого количества языков программирования. В настоящее время существуют в основном
- B4J
- Clojure
- ColdFusion (CFML)
- Erlang
- Go
- Groovy
- Haskell
- Java
- JavaScript
- kotlin
- Lua
- .NET
- OCaml
- Perl
- PHP
- Python
- R
- Ruby
- Rust
- Scala
- Smalltalk
- Vert.x
Обычно мы разрабатываем на Java. Итак, здесь я расскажу о том, как используются Java API Elastic Search.
Готов к работе
Чтобы проиллюстрировать возможности API Java, мы подготовили сценарий. Здесь мы предполагаем набор авторов, у каждого автора есть идентификатор, имя, пол, возраст, описание нескольких полей. Нам нужно запросить автора по имени, возрасту, ключевым словам в описании,
Здесь программа в основном запускается через тестовый пример JUnit, поэтому сначала вводится зависимость JUnit.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Обзор API Java
Elastic Search предоставляет официальные API Java. Здесь есть две категории: Low Level Rest Api (низкоуровневый Rest Api) и High Leve Rest Api (высокоуровневый Rest Api).
Так называемый низкоуровневый API означает не то, что функция относительно слаба, а то, что API относительно близок к базовой реализации. Официальный низкоуровневый API — это первый уровень инкапсуляции оригинального Rest API. Просто инкапсулирует детали вызова Http. Программе все еще нужно собрать строку условия запроса, проанализировать возвращаемую строку результата json и так далее. В то же время ему также необходимо иметь дело с различными методами и заголовками протокола http.
Высокоуровневый API — это дальнейшая инкапсуляция низкоуровневого API. Вам не нужно заботиться о методе интерфейса, заголовке протокола или ручной комбинации строки параметров вызова. определенный анализ возвращаемой строки json. Это более удобно в использовании. Но высокоуровневый API не реализует все функции, которые реализует низкоуровневый API. Поэтому, если вы столкнулись с такой ситуацией, вам также необходимо использовать низкоуровневый API для реализации собственных функций.
Сторонний Java-клиент — это клиент Elastic Search, разработанный сообществом. Официально упомянуты два проекта с открытым исходным кодом на GitHub.Flummi,Jest
Инструкции по использованию Java Low Level Rest API
Преимущество низкоуровневых API в том, что очень мало зависимостей от других библиотек и они полностью функциональны. Недостатком является то, что упаковка недостаточно продвинута, поэтому она все еще очень громоздка в использовании. Давайте сначала посмотрим, как используется низкоуровневый API.
импортировать зависимости
在前面建立的 Maven Java 工程中,要使用 Elastic Search 的低级 Api,首先要引入 低级 Api 的依赖。 Следующее
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.1.1</version>
</dependency>
построить клиент
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")).build();
Мы создаем клиент Elastic Search Rest с помощью статических методов builder(HttpHost... hosts) и builder() объекта RestClient. Где hosts — переменный параметр, используемый для указания IP-адреса, порта и протокола узлов кластера Elastic Cluster.
вызов метода
После установки клиента Rest Api вызывается двумя способами. Один синхронный, другой асинхронный.
Синхронный вызов
Объявление основного метода для синхронного вызова выглядит так:
public Response performRequest(String method, String endpoint, Header... headers) throws IOException
public Response performRequest(String method, String endpoint, Map<String, String> params, Header... headers) throws IOException
public Response performRequest(String method, String endpoint, Map<String, String> params,
HttpEntity entity, Header... headers) throws IOException
Это три перегруженных метода.Метод параметра представляет метод Rest Api, например PUT, GET, POST, DELETE и т. д.; конечная точка параметра представляет собой адрес параметра Rest Api из поля ip:port в Rest URL-адрес API После этого; params — это параметр, передаваемый в виде параметров URL-адреса; entity — параметр, передаваемый через тело http; headers — переменный параметр, который может быть передан в соответствующей информации http-заголовка.
Например, я хочу просмотреть информацию об индексе author_test, мы можем использовать следующий код, чтобы получить
Response response = restClient.performRequest("GET", "/author_test");
В другом примере, если мы хотим просмотреть документальную информацию о программном обеспечении, содержащуюся в поле des индекса author_test, мы можем использовать следующий код для ее получения:
String queryJson = "{\n" +
" \"query\": {\n" +
" \"match\": {\n" +
" \"des\": \"软件\"\n" +
" }\n" +
" }\n" +
"}";
Response response = restClient.performRequest("POST",
"/author_test/_search",
new HashMap<String, String>(),
new NStringEntity(queryJson,ContentType.APPLICATION_JSON));
Асинхронный звонок
Параметры асинхронного вызова и синхронного вызова одинаковы, но асинхронный вызов не имеет возвращаемого значения, но имеет объект обратного вызова отзывчика в параметре, который автоматически вызывается после завершения вызова. Этот объект обратного вызова - это интерфейс, который программист должен использовать самостоятельно.
Объявление метода для асинхронного вызова выглядит так:
public void performRequestAsync(String method, String endpoint, ResponseListener responseListener, Header... headers)
public void performRequestAsync(String method, String endpoint, Map<String, String> params,
ResponseListener responseListener, Header... headers)
public void performRequestAsync(String method, String endpoint, Map<String, String> params,
HttpEntity entity, ResponseListener responseListener, Header... headers)
Например, я хочу запросить все документы, содержащие «программное обеспечение» в индексе author_test, в асинхронном вызове, код реализован следующим образом
String queryJson = "{\n" +
" \"query\": {\n" +
" \"match\": {\n" +
" \"des\": \"软件\"\n" +
" }\n" +
" }\n" +
"}";
restClient.performRequestAsync("POST",
"/author_test/_search",
new HashMap<String, String>(),
new NStringEntity(queryJson, ContentType.APPLICATION_JSON), new ResponseListener() {
public void onSuccess(Response response) {
try {
String responseData = readResposne(response);
System.out.println("******* search success ******");
System.out.println(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onFailure(Exception exception) {
exception.printStackTrace();
}
});
Инструкции по использованию Java High Level Rest API
Высокоуровневый API Elastic Search для Java более абстрактен, чем низкоуровневый API. Однако лично мне трудно им пользоваться. И расширенный API не поддерживает все функции Rest API. Официально поддерживается расширенными APIсписок функций.从这里看,如果你只是做查询,用高级 Api 接口还是够用的。
импортировать зависимости
В созданном ранее проекте Maven Java для использования низкоуровневого API Elastic Search мы должны сначала ввести зависимость низкоуровневого API. Следующее
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.1.1</version>
</dependency>
построить клиент
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")));
Подобно низкоуровневому интерфейсу, сначала создайте объект RestClientBuilder с помощью метода static method builder(HttpHost... hosts) объекта RestClient, а затем используйте его в качестве параметра конструктора объекта RestHighLevelClient для создания нового высокоуровневого объекта. клиентский объект. Где hosts — переменный параметр, используемый для указания IP-адреса, порта и протокола узлов кластера Elastic Cluster.
вызов метода
Здесь высокоуровневый интерфейс используется для реализации функции первого запроса в низкоуровневом интерфейсе. код показывает, как показано ниже
SearchRequest searchRequest = new SearchRequest("author_test");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("des", "软件"));
sourceBuilder.from(0);
sourceBuilder.size(5);
searchRequest.source(sourceBuilder);
SearchResponse response = restClient.search(searchRequest);
Другие вызовы интерфейса могут найти соответствующий API.Описание документаЧто нужно сделать
полный код
В последней главе публикуется полный код.
код инициализации
Эта часть кода отвечает за инициализацию индекса и индексацию документов для теста. Следует отметить, что ранее мы говорили, что Elastic Search — это система квази-реального времени, поэтому после индексации документов, если вы сделаете запрос сразу, вы не сможете запросить данные, и требуется небольшая задержка.
package com.x9710.es.test;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class IndexInitUtil {
public RestClient initLowLevelClient() {
// 通过 ip 、port 和协议建立 Elastic Search 客户端
RestClient restClient = RestClient.builder(
new HttpHost("10.110.2.53", 9200, "http")).build();
try {
initIndex(restClient);
} catch (Exception e) {
e.printStackTrace();
}
return restClient;
}
public RestHighLevelClient initHighLevelClient() {
// 通过 ip 、port 和协议建立 Elastic Search 客户端
RestHighLevelClient highLevelClient = new RestHighLevelClient(
RestClient.builder(
new HttpHost("10.110.2.53", 9200, "http"))
);
RestClient restClient = RestClient.builder(
new HttpHost("10.110.2.53", 9200, "http")).build();
try {
initIndex(restClient);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
restClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return highLevelClient;
}
private void initIndex(RestClient restClient) {
String authIndexDefine = "{\n" +
"\t\"settings\" : {\n" +
" \"index\" : {\n" +
" \"number_of_shards\" : 6,\n" +
" \"number_of_replicas\" : 0\n" +
" }\n" +
" },\n" +
" \"mappings\": {\n" +
" \"doc\": {\n" +
" \"properties\": {\n" +
" \t\"id\": {\"type\": \"text\"},\n" +
" \"name\": {\"type\": \"text\"},\n" +
" \"sex\": {\"type\": \"text\"},\n" +
" \"age\": {\"type\": \"integer\"},\n" +
" \"des\":{\n" +
" \t\"type\":\"text\",\n" +
" \t\"analyzer\": \"ik_max_word\",\n" +
"\t\t\t\t\t\"search_analyzer\": \"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
HttpEntity authorIndexEntity = new NStringEntity(authIndexDefine, ContentType.APPLICATION_JSON);
//初始化要索引的 author 文档列表
List<HttpEntity> authorDocs = new ArrayList<HttpEntity>();
authorDocs.add(new NStringEntity(" {\n" +
"\t\"id\":\"A1001\",\n" +
"\t\"name\":\"任盈盈\",\n" +
"\t\"age\":24,\n" +
"\t\"sex\":\"女\",\n" +
"\t\"des\":\"IT软件工程师,擅长Java和软件架构\"\n" +
" }", ContentType.APPLICATION_JSON));
authorDocs.add(new NStringEntity(" {\n" +
"\t\"id\":\"A1002\",\n" +
"\t\"name\":\"风清扬\",\n" +
"\t\"age\":47,\n" +
"\t\"sex\":\"男\",\n" +
"\t\"des\":\"IT软件技术经理,擅长技术管理过程控制\"\n" +
" }", ContentType.APPLICATION_JSON));
try {
//创建 author_test 索引
restClient.performRequest("PUT", "/author_test", new HashMap<String, String>(), authorIndexEntity);
//索引 author_index 文档
for (int i = 0; i < authorDocs.size(); i++) {
restClient.performRequest("POST", "/author_test/doc", new HashMap<String, String>(), authorDocs.get(i));
}
//注意索引文档完成后,做一个小的延迟,保证后续查询能查到数据
Thread.currentThread().sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Тестовый образец низкоуровневого API
package com.x9710.es.test;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.codehaus.jettison.json.JSONObject;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseListener;
import org.elasticsearch.client.RestClient;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
/**
* Elastic Search 低级 Api 测试类
*
* @author 杨高超
* @since 2018-01-11
*/
public class LowLeveApiTest {
RestClient restClient = null;
@Before
public void before() {
restClient = new IndexInitUtil().initLowLevelClient();
}
@Test
public void testLocateAuthorIndex() {
try {
Response response = restClient.performRequest("GET", "/author_test");
String responseData = readResposne(response);
Assert.assertTrue(new JSONObject(responseData).has("author_test"));
System.out.println(responseData);
} catch (Exception e) {
e.printStackTrace();
Assert.assertTrue(false);
}
}
@Test
public void testQueryAuthDoc() {
try {
String queryJson = "{\n" +
" \"query\": {\n" +
" \"match\": {\n" +
" \"des\": \"Java\"\n" +
" }\n" +
" }\n" +
"}";
Response response = restClient.performRequest("POST",
"/author_test/_search",
new HashMap<String, String>(),
new NStringEntity(queryJson, ContentType.APPLICATION_JSON));
String responseData = readResposne(response);
JSONObject responseJson = new JSONObject(responseData);
Assert.assertTrue(responseJson.has("hits")
&& responseJson.getJSONObject("hits").getInt("total") == 1);
System.out.println(responseData);
} catch (Exception e) {
e.printStackTrace();
Assert.assertTrue(false);
}
}
@Test
public void testQueryAuthDocAsy() {
try {
String queryJson = "{\n" +
" \"query\": {\n" +
" \"match\": {\n" +
" \"des\": \"软件\"\n" +
" }\n" +
" }\n" +
"}";
restClient.performRequestAsync("POST",
"/author_test/_search",
new HashMap<String, String>(),
new NStringEntity(queryJson, ContentType.APPLICATION_JSON), new ResponseListener() {
public void onSuccess(Response response) {
try {
String responseData = readResposne(response);
System.out.println("******* search success ******");
System.out.println(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onFailure(Exception exception) {
exception.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
Assert.assertTrue(false);
}
}
@After
public void after() {
try {
if (restClient != null) {
restClient.performRequest("DELETE", "/author_test");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (restClient != null) {
try {
restClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private String readResposne(Response response) throws Exception {
BufferedReader brd = new BufferedReader(new BufferedReader(new InputStreamReader(response.getEntity().getContent())));
String line;
StringBuilder respongseContext = new StringBuilder();
while ((line = brd.readLine()) != null) {
respongseContext.append(line).append("\n");
}
//rd.close();
if (respongseContext.length() > 0) {
respongseContext.deleteCharAt(respongseContext.length() - 1);
}
return respongseContext.toString();
}
}
Продвинутый образец теста API
package com.x9710.es.test;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Elastic Search 高级 Api 测试类
*
* @author 杨高超
* @since 2018-01-11
*/
public class HighLevelApiTest {
RestHighLevelClient restClient = null;
@Before
public void before() {
restClient = new IndexInitUtil().initHighLevelClient();
}
@Test
public void testQueryAuthDoc() {
try {
SearchRequest searchRequest = new SearchRequest("author_test");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("des", "软件"));
sourceBuilder.from(0);
sourceBuilder.size(5);
searchRequest.source(sourceBuilder);
SearchResponse response = restClient.search(searchRequest);
Assert.assertTrue(response.getHits().getTotalHits() == 2);
System.out.println(response.toString());
} catch (Exception e) {
e.printStackTrace();
Assert.assertTrue(false);
}
}
@After
public void after() {
try {
if (restClient != null) {
restClient.indices().deleteIndex(new DeleteIndexRequest("author_test"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (restClient != null) {
try {
restClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
постскриптум
Как упоминалось ранее, сообщество также предоставило множество клиентских библиотек Elastic Search, но времени на их изучение нет. Если кто-то использовал его и нашел его полезным, я хотел бы порекомендовать его.
Первоначально опубликовано вкороткая книганачальство.