在今天的文章中,咱們來介紹如何使用Java來訪問Elasticsearch。html
首先,咱們必須在咱們的系統中安裝Elasticsearch。java
針對Java的開發,咱們必須在pom.xml中配置相應的Elasticsearch的信息。Mavev dependency定義以下:git
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.3.1</version> </dependency>
這也是目前截止最新的Elasticsearch的版本。您能夠隨時使用以前提供的連接查看Maven Central託管的最新版本。github
package com.javacodegeeks.example; public class Person { private String personId; private String name; private String number; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getPersonId() { return personId; } public void setPersonId(String personId) { this.personId = personId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return String.format("Person{personId='%s', name='%s', number='%s}", personId, name, number); } }
在這裏,咱們定義了一個簡單的Person Model。數據庫
咱們將使用默認鏈接參數與Elasticsearch創建鏈接。 默認狀況下,ES使用兩個端口:9200和9201json
private static final String HOST = "localhost"; private static final int PORT_ONE = 9200; private static final int PORT_TWO = 9201; private static final String SCHEME = "http"; private static RestHighLevelClient restHighLevelClient; private static ObjectMapper objectMapper = new ObjectMapper(); private static final String INDEX = "persondata"; private static final String TYPE = "_doc";
這裏咱們定義了一個叫作persondata的index,它的type是_doc。在最新的版本中,每一個index只支持一個type。安全
如上面參數中所述,Elasticsearch使用兩個端口9200和9201.第一個端口9200由Elasticsearch查詢服務器使用,咱們可使用它經過RESTful API直接查詢數據庫。 第二個端口9201由REST服務器使用,外部客戶端可使用該端口鏈接並執行操做。服務器
咱們將建立一個與Elasticsearch數據庫創建鏈接的方法。 在創建與數據庫的鏈接時,咱們必須提供兩個端口,由於只有這樣,咱們的應用程序才能鏈接到Elasticsearch服務器,咱們將可以執行數據庫操做。 如下是創建鏈接的代碼。app
private static synchronized RestHighLevelClient makeConnection() { if(restHighLevelClient == null) { restHighLevelClient = new RestHighLevelClient( RestClient.builder( new HttpHost(HOST, PORT_ONE, SCHEME), new HttpHost(HOST, PORT_TWO, SCHEME))); } return restHighLevelClient; }
在這裏,咱們創建一個RestHighLevelClient的實例。具體的參數,能夠參官方文檔 Java High Level REST Client (https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high.html)。dom
請注意,咱們在此處實現了Singleton Design模式,所以不會爲ES建立多個鏈接,從而節省大量內存。
因爲存在RestHighLevelClient,與Elasticsearch的鏈接是線程安全的。 初始化此鏈接的最佳時間是應用程序請求或向客戶端發出第一個請求時。 初始化此鏈接客戶端後,可使用它來執行任何支持的API。
就像在早期版本的Elasticsearch中同樣,咱們使用TransportClient,一旦完成查詢就關閉它,一旦數據庫交互完成RestHighLevelClient,也須要關閉鏈接。 如下是如何作到這一點:
private static synchronized void closeConnection() throws IOException { restHighLevelClient.close(); restHighLevelClient = null; }
咱們還爲RestHighLevelClient對象分配了null,以便Singleton模式能夠保持一致。
咱們能夠經過將鍵和值轉換爲HashMap將數據插入數據庫。 ES數據庫僅接受HashMap形式的值。 讓咱們看看如何實現這一目標的代碼片斷:
private static Person insertPerson(Person person) { person.setPersonId(UUID.randomUUID().toString()); Map<String, Object> dataMap = new HashMap<String, Object>(); dataMap.put("name", person.getName()); dataMap.put("number", person.getNumber()); IndexRequest indexRequest = new IndexRequest(INDEX) .id(person.getPersonId()).source(dataMap); try { IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); } catch(ElasticsearchException e) { e.getDetailedMessage(); } catch (java.io.IOException ex){ ex.getLocalizedMessage(); } /* // The following is another way to do it // More information https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-document-index.html String id = UUID.randomUUID().toString(); person.setPersonId(id); IndexRequest request = new IndexRequest(INDEX); request.id(id); String jsonString = "{" + "\"name\":" + "\"" + person.getName() + "\"" + "}"; System.out.println("jsonString: " + jsonString); request.source(jsonString, XContentType.JSON); try { IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT); } catch(ElasticsearchException e) { e.getDetailedMessage(); } catch (java.io.IOException ex){ ex.getLocalizedMessage(); } */ return person; }
就像上面代碼中註釋的那樣。註釋的代碼的那一部分是另一種方法。你們能夠參照連接(https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-document-index.html)得到更多的信息。
上面,咱們使用Java的UUID類來建立對象的惟一標識符。 這樣,咱們就能夠控制對象標識符的製做方式。咱們其實也能夠固定一個id去寫。若是是這樣的話,運行屢次,只會更新以前的數據,而且version會自動每次運行後增長1。
完成將數據插入數據庫後,咱們能夠經過向Elasticsearch數據庫服務器發出GET請求來確認操做。 讓咱們看看如何完成此操做的代碼片斷:
private static Person getPersonById(String id){ GetRequest getPersonRequest = new GetRequest(INDEX, id); GetResponse getResponse = null; try { getResponse = restHighLevelClient.get(getPersonRequest, RequestOptions.DEFAULT); } catch (java.io.IOException e){ e.getLocalizedMessage(); } return getResponse != null ? objectMapper.convertValue(getResponse.getSourceAsMap(), Person.class) : null; }
在這裏,咱們根據上面返回來得id來進行query,並返回數據。
在這個查詢中,咱們只提供了能夠識別它的對象的主要信息,即索引,和它的惟一標識符id。 此外,咱們獲得的其實是一個值的映射。
咱們能夠經過首先使用其索引,類型和惟一標識符來標識資源,從而輕鬆地向Elasticsearch發出更新請求。 而後咱們可使用新的HashMap對象來更新Object中的任意數量的值。 這是一個示例代碼段:
private static Person updatePersonById(String id, Person person){ UpdateRequest updateRequest = new UpdateRequest(INDEX, id) .fetchSource(true); // Fetch Object after its update try { String personJson = objectMapper.writeValueAsString(person); updateRequest.doc(personJson, XContentType.JSON); UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); return objectMapper.convertValue(updateResponse.getGetResult().sourceAsMap(), Person.class); }catch (JsonProcessingException e){ e.getMessage(); } catch (java.io.IOException e){ e.getLocalizedMessage(); } System.out.println("Unable to update person"); return null; }
最後,咱們能夠經過簡單地使用其索引,類型和惟一標識符來標識資源來刪除數據。 讓咱們看一下如何完成此操做的代碼片斷
private static void deletePersonById(String id) { DeleteRequest deleteRequest = new DeleteRequest(INDEX, TYPE, id); try { DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); } catch (java.io.IOException e) { e.getLocalizedMessage(); } }
咱們根據傳入的id來刪除相應的文檔。固然咱們也能夠作查詢刪除。
讓咱們經過執行上面提到的全部操做來嘗試咱們的應用程序。 因爲這是一個普通的Java應用程序,咱們將調用這些方法中的每個並打印操做結果:
public static void main(String[] args) throws IOException { makeConnection(); Person person = new Person(); person.setName("張三"); System.out.println("Inserting a new Person with name " + person.getName()); person.setNumber("111111"); person = insertPerson(person); System.out.println("Person inserted --> " + person); person = new Person(); person.setName("姚明"); System.out.println("Inserting a new Person with name " + person.getName()); person.setNumber("222222"); person = insertPerson(person); System.out.println("Person inserted --> " + person); person.setName("李四"); System.out.println("Changing name to " + person.getName()); updatePersonById(person.getPersonId(), person); System.out.println("Person updated --> " + person); System.out.println("Searching for all documents"); SearchResponse response = searchAll(); System.out.println(response); System.out.println("Searching for a term"); response = searchTerm(); System.out.println(response); System.out.println("Match a query"); response = matchQuery(); System.out.println(response); System.out.println("Getting 李四"); Person personFromDB = getPersonById(person.getPersonId()); System.out.println("Person from DB --> " + personFromDB); System.out.println("Deleting " + person.getName()); deletePersonById(personFromDB.getPersonId()); System.out.println("Person " + person.getName() + " deleted!"); closeConnection(); }
運行的結果以下:
Inserting a new Person with name 張三 Person inserted --> Person{personId='33f4162e-0a68-4e66-8717-851516272185', name='張三', number='111111} Inserting a new Person with name 姚明 Person inserted --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='姚明', number='222222} Changing name to 李四 Person updated --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='李四', number='222222} Searching for all documents {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":4,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":1.0,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":1.0,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":1.0,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"468dabe4-8f50-4667-a165-9ce6e015cb76","_score":1.0,"_source":{"number":"222222","name":"李四","personId":"468dabe4-8f50-4667-a165-9ce6e015cb76"}}]}} Searching for a term {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"relation":"eq"},"max_score":0.9444616,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":0.9444616,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":0.9444616,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":0.9444616,"_source":{"number":"111111","name":"張三"}}]}} Match a query {"took":0,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":3,"relation":"eq"},"max_score":1.8889232,"hits":[{"_index":"persondata","_type":"_doc","_id":"52425a44-dc06-49ca-b3df-26a8b341391c","_score":1.8889232,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"c76b8670-ed00-4212-b47b-46bc85d588b6","_score":1.8889232,"_source":{"number":"111111","name":"張三"}},{"_index":"persondata","_type":"_doc","_id":"b8bf0466-0ea5-43e0-8188-c0712812fb9a","_score":1.8889232,"_source":{"number":"111111","name":"張三"}}]}} Getting 李四 Person from DB --> Person{personId='9b477529-6e79-42e8-a50a-21b2d8bc4c13', name='李四', number='222222}
整個項目的源碼能夠在地址找到:https://github.com/liu-xiao-guo/elastic-java
更多資料:
【1】使用RestHighLevelClient時單個索引速度很慢(https://discuss.elastic.co/t/resthighlevelclient/170293)