說明
High Level Client 是基於 Low Level Client 的。官方文檔如下:
* https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html
* https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
依賴
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>6.5.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.11.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>6.5.0</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.5.0</version> </dependency>
連接
import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; /** * Java高級REST客戶機在Java低級REST客戶機之上工作。它的主要目標是公開特定於API的方法,這些方法接受請求對象作為參數並返回響應對象 * 可以同步或異步調用每個API。同步方法返回一個響應對象,而異步方法(其名稱以async后綴結尾)需要一個偵聽器參數 * 一旦接收到響應或錯誤,偵聽器參數(在低層客戶機管理的線程池上)將被通知。 * Java高級REST客戶機依賴於Elasticsearch核心項目。它接受與TransportClient相同的請求參數,並返回相同的響應對象。 * Java高級REST客戶機需要Java 1.8 * 客戶機版本與開發客戶機的Elasticsearch版本相同 * 6.0客戶端能夠與任意6.X節點通信,6.1客戶端能夠與6.1、6.2和任意6.X通信 */ public class RestClientFactory { private RestClientFactory(){} private static class Inner{ private static final RestClientFactory instance = new RestClientFactory(); } public static RestClientFactory getInstance(){ return Inner.instance; } public RestHighLevelClient getClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //new HttpHost("localhost", 9201, "http"), new HttpHost("localhost", 9200, "http") ) ); return client; } }
【JavaAPI與HTTP請求】
1. Index
HTTP請求
查看所有數據
GET twitter/t_doc/_search
---
# 添加數據[index]/[type]/[id] PUT twitter/t_doc/10 { "user" : "kimchy", "post_date" : "2018-12-24T11:32:00", "message" : "trying out Elasticsearch" }
結果:
{ "_index" : "twitter", "_type" : "t_doc", "_id" : "10", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 1 }
Java
public static RestHighLevelClient index() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("user", "kimchy"); jsonMap.put("postDate", new Date()); jsonMap.put("message", "trying out Elasticsearch"); IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "1") .source(jsonMap); IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); System.out.println(response.status().name()); return client; }
結果:
CREATED
還有兩種形式添加數據
/** * 方式二:XContentBuilder * @return * @throws IOException */ public static RestHighLevelClient index2() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); XContentBuilder builder = jsonBuilder(); builder.startObject(); { builder.field("user", "kimchy"); builder.timeField("postDate", new Date()); builder.field("message", "trying out Elasticsearch"); } builder.endObject(); IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "2") .source(builder); IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); System.out.println(response.status().name()); return client; } /** * 方式三:Object key-pairs對象鍵 * 同步方法 * @return * @throws IOException */ public static RestHighLevelClient index3() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "3") .source("user", "kimchy", "postDate", new Date(), "message", "trying out Elasticsearch"); IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); // 同步方式 System.out.println(response.status().name()); return client; }
還能異步創建&添加數據
/** * 異步方法 * @return * @throws IOException */ public static RestHighLevelClient index4() throws IOException, InterruptedException { ActionListener listener = new ActionListener<IndexResponse>() { @Override public void onResponse(IndexResponse indexResponse) { System.out.println("Async:" + indexResponse.status().name()); if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) { // Todo } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) { // Todo } // 處理成功分片小於總分片的情況 ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo(); if (shardInfo.getTotal() != shardInfo.getSuccessful()) { // Todo } } @Override public void onFailure(Exception e) { System.out.println("AsyncFailure:" + e.getMessage()); e.printStackTrace(); } }; RestHighLevelClient client = RestClientFactory.getInstance().getClient(); IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "4") .source("user", "kimchy", "postDate", new Date(), "message", "trying out Elasticsearch") .routing("my_route"); // 指定路由 client.indexAsync(indexRequest, RequestOptions.DEFAULT, listener); // 異步方式 Thread.sleep(2000); return client; }
結果:
Async:CREATED
2. Get
HTTP請求
# 獲取數據 GET twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "postDate" : "2018-12-24T03:42:22.787Z", "message" : "trying out Elasticsearch", "user" : "kimchy" } }
可以指定routing
GET twitter/t_doc/4?routing=my_route 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "4", "_version" : 1, "_routing" : "my_route", "found" : true, "_source" : { "user" : "kimchy", "postDate" : "2018-12-24T06:08:45.178Z", "message" : "trying out Elasticsearch" } }
可以只要數據信息_source
GET twitter/t_doc/4/_source?routing=my_route 結果: { "user" : "kimchy", "postDate" : "2018-12-24T06:08:45.178Z", "message" : "trying out Elasticsearch" }
Java
public static RestHighLevelClient getOne() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetRequest request = new GetRequest("twitter", "t_doc", "4").routing("my_route"); // 指定routing的數據,查詢也要指定 try { GetResponse response = client.get(request, RequestOptions.DEFAULT); System.out.println(response.getSourceAsString()); } catch (ElasticsearchException e) { // 處理找不到index的異常 if(e.status() == RestStatus.NOT_FOUND){ // TODO } } return client; }
結果:
{"user":"kimchy","postDate":"2018-12-24T06:08:45.178Z","message":"trying out Elasticsearch"}
異步獲取,並且指定包含/排除的字段
/** * 查詢-額外參數 * 異步獲取 * @return * @throws IOException */ public static RestHighLevelClient getOneOp() throws IOException, InterruptedException { ActionListener<GetResponse> listener = new ActionListener<GetResponse>() { @Override public void onResponse(GetResponse documentFields) { System.out.println(documentFields.getSourceAsString()); } @Override public void onFailure(Exception e) { System.out.println("Error:" + e.getMessage()); e.printStackTrace(); } }; RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetRequest request = new GetRequest("twitter", "t_doc", "1"); String[] includes = new String[]{"message", "*Date"}; // 包含的字段 String[] excludes = Strings.EMPTY_ARRAY; // 排除的字段 FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes); request.fetchSourceContext(fetchSourceContext); client.getAsync(request, RequestOptions.DEFAULT, listener); Thread.sleep(2000); return client; }
結果:
{"postDate":"2018-12-24T03:42:22.787Z","message":"trying out Elasticsearch"}
到這里也應該知道,Rest API 對每個操作提供了同步/異步的方法。
3. Exist API
Java
/** * 檢查是否存在 * @return * @throws IOException */ public static RestHighLevelClient exist() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetRequest request = new GetRequest("twitter", "t_doc", "1"); request.storedFields("_none_"); // 禁用獲取存儲字段 request.fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE); // 禁用抓取_source boolean exists = client.exists(request, RequestOptions.DEFAULT); System.out.println(exists); return client; }
結果:
true
4. Delete API
HTTP請求
DELETE twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 2, "result" : "deleted", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1 }
Java
/** * 刪除也可以異步、也可以捕獲異常,成功刪除的分片數量,版本沖突 * @return * @throws IOException */ public static RestHighLevelClient deleteOne() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); DeleteRequest request = new DeleteRequest("twitter", "t_doc", "1"); DeleteResponse response = client.delete(request, RequestOptions.DEFAULT); System.out.println(response.status().name()); // 處理找不到的情況 if (response.getResult() == DocWriteResponse.Result.NOT_FOUND) { // TODO } return client; }
結果:
NOT_FOUND
5. Delete By Query API
我這里有4條測試數據
{"user":"Tom","flag":"1"} {"user":"foo","flag":"2"} {"user":"bar","flag":"2"} {"user":"baz","flag":"2"}
HTTP 請求
# 刪除flag=2的數據 POST twitter/_delete_by_query?conflicts=proceed { "query": { "match": { "flag": "2" } } } 結果: { "took" : 183, "timed_out" : false, "total" : 3, "deleted" : 3, "batches" : 1, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] }
--擴展
# 清空索引全部數據 POST /[索引名]/_delete_by_query { "query": { "match_all": {} } }
Java
/** * 根據查詢條件刪除 * @return * @throws IOException */ public static RestHighLevelClient deleteByQuery() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); DeleteByQueryRequest request = new DeleteByQueryRequest("twitter"); request.setConflicts("proceed"); // 發生沖突即略過 request.setQuery(QueryBuilders.matchQuery("flag","2")); BulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT); TimeValue timeTaken = bulkResponse.getTook(); boolean timedOut = bulkResponse.isTimedOut(); long totalDocs = bulkResponse.getTotal(); long updatedDocs = bulkResponse.getUpdated(); long deletedDocs = bulkResponse.getDeleted(); long batches = bulkResponse.getBatches(); long noops = bulkResponse.getNoops(); long versionConflicts = bulkResponse.getVersionConflicts(); System.out.println("花費時間:" + timeTaken + ",是否超時:" + timedOut + ",總文檔數:" + totalDocs + ",更新數:" + updatedDocs + ",刪除數:" + deletedDocs + ",批量次數:" + batches + ",跳過數:" + noops + ",沖突數:" + versionConflicts); List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures(); // 搜索期間的故障 searchFailures.forEach(e -> { System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId()); }); List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures(); // 批量索引期間的故障 bulkFailures.forEach(e -> { System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId()); }); return client; }
結果:
花費時間:97ms,是否超時:false,總文檔數:3,更新數:0,刪除數:3,批量次數:1,跳過數:0,沖突數:0
6. Update API
我有一條測試數據
{"user":"Tom","flag":"1"}
HTTP 請求
# 通過腳本更新 POST twitter/t_doc/1/_update { "script" : { "source": "ctx._source.msg = params.msg", "lang": "painless", "params" : { "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない" } } } # 通過文檔更新 POST twitter/t_doc/1/_update { "doc" : { "user" : "new_name" } }
upserts
# upserts(如果文檔不存在,則把upsert里面的內容作為文檔插入) POST twitter/t_doc/2/_update { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } }, "upsert" : { "counter" : 1 } } 結果【創建新文檔】: { "_index" : "twitter", "_type" : "t_doc", "_id" : "2", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1 }
如果你再執行的話就是更新了
結果【更新文檔】: { "_index" : "twitter", "_type" : "t_doc", "_id" : "2", "_version" : 2, "result" : "updated", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 2, "_primary_term" : 1 } 查詢: GET twitter/t_doc/2 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "2", "_version" : 2, "found" : true, "_source" : { "counter" : 5 } }
不用腳本而用文檔更新
# 如果文檔不存在,則將doc內容作為新文檔插入(因為"doc_as_upsert" : true) POST twitter/t_doc/3/_update { "doc" : { "name" : "new_name" }, "doc_as_upsert" : true } 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "3", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 5, "_primary_term" : 1 } 查詢: GET twitter/t_doc/3 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "3", "_version" : 1, "found" : true, "_source" : { "name" : "new_name" } }
Java
/** * 通過腳本更新,可以添加字段 * @return */ public static RestHighLevelClient updateOne() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1"); Map<String, Object> parameters = singletonMap("msg", "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない"); Script inline = new Script(ScriptType.INLINE, "painless", "ctx._source.msg = params.msg", parameters); request.script(inline); UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); return client; }
輸出:OK
GET twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 4, "found" : true, "_source" : { "user" : "Tom", "flag" : "1", "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない" } }
還可以通過XContentBuilder
/** * 通過XContentBuilder更新 * @return * @throws IOException */ public static RestHighLevelClient updateOne2() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); XContentBuilder builder = jsonBuilder() .startObject() .startObject("animal") .field("cat", "阿貓") .field("dog", "阿狗") .endObject() .endObject(); UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1").doc(builder); UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); return client; }
輸出:OK
GET twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 5, "found" : true, "_source" : { "user" : "Tom", "flag" : "1", "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない", "animal" : { "cat" : "阿貓", "dog" : "阿狗" } } }
還可以通過Map
/** * 通過jsonMap更新 * @return * @throws IOException */ public static RestHighLevelClient updateOne3() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("updateUser", "Jack Ma"); UpdateRequest request = new UpdateRequest("posts", "doc", "1").doc(jsonMap); UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); return client; }
輸出:OK
GET twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 6, "found" : true, "_source" : { "user" : "Tom", "flag" : "1", "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない", "animal" : { "cat" : "阿貓", "dog" : "阿狗" }, "updateUser" : "Jack Ma" } }
還可以通過 key-pairs
/** * 通過 key-pairs 更新 * @return * @throws IOException */ public static RestHighLevelClient updateOne4() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1") .doc("favorite","二狗","hate","no Money"); UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); return client; }
輸出:OK
GET twitter/t_doc/1 結果: { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 7, "found" : true, "_source" : { "user" : "Tom", "flag" : "1", "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない", "animal" : { "cat" : "阿貓", "dog" : "阿狗" }, "updateUser" : "Jack Ma", "hate" : "no Money", "favorite" : "二狗" } }
upserts
/** * 存在即更新【輸出:OK】 * OK * {"C":"Carambola","A":"Apple","B":"Banana"} * 不存在則創建【輸出:CREATED】 * CREATED * {"C":"Carambola"} * 開啟scriptedUpsert【在文檔不存在情況下輸出:CREATED】 * {"A" : "Apple","B" : "Banana","C" : "Carambola"} * @return * @throws IOException */ public static RestHighLevelClient upserts() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); UpdateRequest request = new UpdateRequest("twitter", "t_doc", "7") .script(new Script(ScriptType.INLINE,"painless", "ctx._source.A='Apple';ctx._source.B='Banana'",Collections.EMPTY_MAP)) // 如果文檔不存在,使用upsert方法定義一些內容,這些內容將作為新文檔插入 .upsert(jsonBuilder() .startObject() .field("C","Carambola") .endObject()); request.timeout(TimeValue.timeValueSeconds(2)); // 2秒超時 //request.scriptedUpsert(true); // 無論文檔是否存在,腳本都必須運行 UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); return client; }
--
/** * 存在即更新 * OK * {"C" : "Carambola","A" : "Apple","B" : "Banana","D" : "Dew"} * 不存在則創建 * CREATED * {"C" : "Carambola"} * 開啟docAsUpsert【在文檔不存在情況下輸出:CREATED】 * {"A" : "Apple","B" : "Banana","D" : "Dew"} * @return * @throws IOException */ public static RestHighLevelClient upserts2() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); UpdateRequest request = new UpdateRequest("twitter", "t_doc", "8") .doc(jsonBuilder() .startObject() .field("A","Apple") .field("B","Banana") .field("D","Dew") .endObject()) // 如果指定docAsUpsert(true),會忽略upsert方法 .upsert(jsonBuilder() .startObject() .field("C","Carambola") .endObject()); //request.docAsUpsert(true); // 如果部分文檔尚不存在,則必須將doc用作upsert文檔 request.timeout(TimeValue.timeValueSeconds(2)); // 2秒超時 try { UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status().name()); } catch (ElasticsearchException e) { if (e.status() == RestStatus.NOT_FOUND) { // TODO } } return client; }
7. Update By Query API
HTTP請求
# 不更改源數據的前提下更新文檔 POST twitter/_update_by_query?conflicts=proceed 結果: { "took" : 186, "timed_out" : false, "total" : 9, "updated" : 9, "deleted" : 0, "batches" : 1, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] }
--
我們有數據:
{ "_index" : "twitter", "_type" : "t_doc", "_id" : "9", "_version" : 3, "found" : true, "_source" : { "flag" : "2", "user" : "foo" } }
# 通過腳本更新 POST twitter/_update_by_query?conflicts=proceed { "script": { "source": "ctx._source.flag++", "lang": "painless" }, "query": { "term": { "user": "foo" } } } 結果: { "took" : 102, "timed_out" : false, "total" : 1, "updated" : 1, "deleted" : 0, "batches" : 1, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] }
Java
/** * 根據查詢條件更新 * @return */ public static RestHighLevelClient updateByQuery() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); UpdateByQueryRequest request = new UpdateByQueryRequest("twitter"); request.setConflicts("proceed"); request.setQuery(QueryBuilders.matchAllQuery()) .setBatchSize(50) // 批處理大小 .setSize(100) // 限制處理文檔的數量 .setScript(new Script( ScriptType.INLINE, "painless", "if (ctx._source.flag == '2') {ctx._source.extMsg = '小林さんちのメイドラゴン';}", // 增加一個字段extMsg Collections.emptyMap())); BulkByScrollResponse bulkResponse = client.updateByQuery(request, RequestOptions.DEFAULT); TimeValue timeTaken = bulkResponse.getTook(); boolean timedOut = bulkResponse.isTimedOut(); long totalDocs = bulkResponse.getTotal(); long updatedDocs = bulkResponse.getUpdated(); long deletedDocs = bulkResponse.getDeleted(); long batches = bulkResponse.getBatches(); long noops = bulkResponse.getNoops(); long versionConflicts = bulkResponse.getVersionConflicts(); System.out.println("花費時間:" + timeTaken + ",是否超時:" + timedOut + ",總文檔數:" + totalDocs + ",更新數:" + updatedDocs + ",刪除數:" + deletedDocs + ",批量次數:" + batches + ",跳過數:" + noops + ",沖突數:" + versionConflicts); List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures(); // 搜索期間的故障 searchFailures.forEach(e -> { System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId()); }); List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures(); // 批量索引期間的故障 bulkFailures.forEach(e -> { System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId()); }); return client; }
結果:【之所以更新了全部文檔,是因為matchAllQuery】
花費時間:218ms,是否超時:false,總文檔數:9,更新數:9,刪除數:0,批量次數:1,跳過數:0,沖突數:0
# 查詢flag=2的文檔 GET /twitter/_search { "query": { "match": { "flag": "2" } } } 結果: { "took" : 0, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 0.6931472, "hits" : [ { "_index" : "twitter", "_type" : "t_doc", "_id" : "10", "_score" : 0.6931472, "_source" : { "flag" : "2", "extMsg" : "小林さんちのメイドラゴン", "user" : "bar" } }, { "_index" : "twitter", "_type" : "t_doc", "_id" : "11", "_score" : 0.2876821, "_source" : { "flag" : "2", "extMsg" : "小林さんちのメイドラゴン", "user" : "baz" } } ] } }
8. Bulk API
HTTP請求
# 批量處理(允許Add,Delete,Update操作)如果包含routing要加上 POST _bulk { "delete" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "9" } } { "update" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "4","routing":"my_route" } } { "doc" : {"user":"new_user"} } { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "21" }} { "user":"Tom","flag":"1" } { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "22" }} { "user":"Tony","flag":"1" } { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "23" }} { "user":"Mary","flag":"1" } { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "24" }} { "user":"Jerry","flag":"1" }
Java
/** * 批量添加 * @return */ public static RestHighLevelClient bulkAdd() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); BulkRequest request = new BulkRequest(); request.add(new IndexRequest("twitter", "t_doc", "25") .source(XContentType.JSON,"user", "Tom","flag","1")); request.add(new IndexRequest("twitter", "t_doc", "26") .source(XContentType.JSON,"user", "foo","flag","2")); request.add(new IndexRequest("twitter", "t_doc", "27") .source(XContentType.JSON,"user", "bar","flag","2")); request.add(new IndexRequest("twitter", "t_doc", "28") .source(XContentType.JSON,"user", "baz","flag","2")); BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT); System.out.println("Status:" + bulk.status().name() + ",hasFailures:" + bulk.hasFailures()); // 下面是multiGet MultiGetRequest multiGetRequest = new MultiGetRequest() .add(new MultiGetRequest.Item("twitter", "t_doc", "25")) .add(new MultiGetRequest.Item("twitter", "t_doc", "26")) .add(new MultiGetRequest.Item("twitter", "t_doc", "27")) .add(new MultiGetRequest.Item("twitter", "t_doc", "28")); MultiGetResponse response = client.mget(multiGetRequest, RequestOptions.DEFAULT); MultiGetItemResponse[] itemResponses = response.getResponses(); for(MultiGetItemResponse r : itemResponses){ System.out.println(r.getResponse().getSourceAsString()); } return client; }
輸出:
Status:OK,hasFailures:false {"user":"Tom","flag":"1"} {"user":"foo","flag":"2"} {"user":"bar","flag":"2"} {"user":"baz","flag":"2"}
也可以批量更新
/** * 批量更新 * @return */ public static RestHighLevelClient bulkUpdate() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); BulkRequest request = new BulkRequest(); // 更新 request.add(new UpdateRequest("twitter", "t_doc", "27") .doc(XContentType.JSON,"field", "foo","color", "red","size", "100")); // 添加 request.add(new IndexRequest("twitter", "t_doc", "29") .source(XContentType.JSON,"field", "bar","color", "blue","size", "200")); // 刪除 request.add(new DeleteRequest("twitter", "t_doc", "28")); BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT); System.out.println("Status:" + bulk.status().name() + ",hasFailures:" + bulk.hasFailures()); // 針對不同類型進行處理 for (BulkItemResponse bulkItemResponse : bulk) { DocWriteResponse itemResponse = bulkItemResponse.getResponse(); if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.INDEX || bulkItemResponse.getOpType() == DocWriteRequest.OpType.CREATE) { IndexResponse indexResponse = (IndexResponse) itemResponse; System.out.println(indexResponse.status().name()); } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.UPDATE) { UpdateResponse updateResponse = (UpdateResponse) itemResponse; System.out.println(updateResponse.status().name()); } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.DELETE) { DeleteResponse deleteResponse = (DeleteResponse) itemResponse; System.out.println(deleteResponse.status().name()); } } String[] includes = Strings.EMPTY_ARRAY; String[] excludes = new String[] {"flag"}; // 包含/排除的字段 FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes); MultiGetRequest multiGetRequest = new MultiGetRequest() .add(new MultiGetRequest.Item("twitter", "t_doc", "29").fetchSourceContext(fetchSourceContext)) .add(new MultiGetRequest.Item("twitter", "t_doc", "28").fetchSourceContext(fetchSourceContext)) .add(new MultiGetRequest.Item("twitter", "t_doc", "27").fetchSourceContext(fetchSourceContext)); MultiGetResponse response = client.mget(multiGetRequest, RequestOptions.DEFAULT); MultiGetItemResponse[] itemResponses = response.getResponses(); for(MultiGetItemResponse r : itemResponses){ System.out.println(r.getResponse().getSourceAsString()); } return client; }
輸出:
Status:OK,hasFailures:false OK CREATED OK {"field":"bar","color":"blue","size":"200"} null {"field":"foo","color":"red","size":"100","user":"bar"}
bulkProcessor就比較厲害了
/** * BulkProcessor通過提供一個實用程序類來簡化Bulk API的使用,它允許索引/更新/刪除操作在添加到處理器時透明地執行。 * 為了執行請求,BulkProcessor需要以下組件: * RestHighLevelClient * 此客戶端用於執行BulkRequest和檢索BulkResponse * BulkProcessor.Listener * 在每個BulkRequest執行之前和之后,或者在BulkRequest失敗時,都會調用這個偵聽器 * BulkProcessor.builder方法可用於構建新的BulkProcessor: * @return */ public static RestHighLevelClient bulkProcessor() throws InterruptedException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); BulkProcessor.Listener listener = new BulkProcessor.Listener() { @Override public void beforeBulk(long executionId, BulkRequest request) { int numberOfActions = request.numberOfActions(); System.out.println("請求數量:" + numberOfActions); } @Override public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { if (response.hasFailures()) { System.out.println("Bulk Failures,ID:" + executionId + ",Status:" + response.status().name()); for (BulkItemResponse bulkItemResponse : response) { if (bulkItemResponse.isFailed()) { BulkItemResponse.Failure failure = bulkItemResponse.getFailure(); System.err.println(failure.getCause().getMessage()); } } } else { System.out.println("Bulk "+ executionId +" Complete in" + response.getTook().getMillis() + "s"); } } @Override public void afterBulk(long executionId, BulkRequest request, Throwable failure) { System.out.println("Failed to execute bulk:" + failure); } }; BiConsumer<BulkRequest, ActionListener<BulkResponse>> bulkConsumer = (request, bulkListener) -> client.bulkAsync(request, RequestOptions.DEFAULT, bulkListener); BulkProcessor bulkProcessor = BulkProcessor.builder(bulkConsumer, listener) .setBulkActions(500) // 請求(Index,Update,Delete)的數量達到500,就刷新一次bulk request【默認1000】 // .setBulkSize(new ByteSizeValue(1L, ByteSizeUnit.MB)) // 累計請求所占的空間達到1M,就刷新一次bulk request【默認5M】 .setConcurrentRequests(0) // 設置允許執行的並發請求數量(默認為1,使用0只允許執行單個請求) // .setFlushInterval(TimeValue.timeValueSeconds(10L)) // 每隔一段時間刷新一次【默認未設置】 .setBackoffPolicy(BackoffPolicy .constantBackoff(TimeValue.timeValueSeconds(1L), 3))// 設置一個初始等待1秒並重試3次的Backoff策略 .build(); for(int i = 1; i <= 2000; i++){ bulkProcessor.add(new IndexRequest("books", "java", ""+i) .source(XContentType.JSON,"title","title_"+i,"user","user_"+i)); } bulkProcessor.flush(); Thread.sleep(2000); bulkProcessor.close(); return client; }
輸出:【警告可忽略,因為默認分片數量在7.0.0版本會改變,這里提醒一下用戶。也就是說,最好先去建立索引(設置好參數),再來添加數據】
請求數量:500 十二月 25, 2018 11:24:06 上午 org.elasticsearch.client.RestClient logResponse 警告: request [POST http://localhost:9200/_bulk?timeout=1m] returned 1 warnings: [299 Elasticsearch-6.5.0-816e6f6 "the default number of shards will change from [5] to [1] in 7.0.0; if you wish to continue using the default of [5] shards, you must manage this on the create index request or with an index template" "Tue, 25 Dec 2018 03:24:04 GMT"] Bulk 1 Complete in2044s 請求數量:500 Bulk 2 Complete in333s 請求數量:500 Bulk 3 Complete in235s 請求數量:500 Bulk 4 Complete in244s
查看:
GET books/_search 結果: { "took" : 18, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 2000, "max_score" : 1.0, "hits" : [ { "_index" : "books", "_type" : "java", "_id" : "14", "_score" : 1.0, "_source" : { "title" : "title_14", "user" : "user_14" } }, .... ] } }
9. Multi-Get API
HTTP 請求
GET /_mget { "docs" : [ { "_index" : "books", "_type" : "java", "_id" : "1" }, { "_index" : "twitter", "_type" : "t_doc", "_id" : "1" } ] } 結果: { "docs" : [ { "_index" : "books", "_type" : "java", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "title" : "title_1", "user" : "user_1" } }, { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 13, "found" : true, "_source" : { "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない", "flag" : "1", "user" : "new_name" } } ] }
GET /twitter/t_doc/_mget { "docs" : [ { "_id" : "1" }, { "_id" : "2" } ] } GET /twitter/t_doc/_mget { "ids" : ["1", "2"] } # 兩個方式效果一樣 結果: { "docs" : [ { "_index" : "twitter", "_type" : "t_doc", "_id" : "1", "_version" : 13, "found" : true, "_source" : { "msg" : "達に攜帯で連絡取ろうと思ったら 電池が切れてて動かない", "flag" : "1", "user" : "new_name" } }, { "_index" : "twitter", "_type" : "t_doc", "_id" : "2", "_version" : 5, "found" : true, "_source" : { "counter" : 5, "user" : "new_user" } } ] }
Java代碼在bulk里面有體現,這里就不贅述了。
10. Reindex API
Reindex不嘗試設置目標索引。它不復制源索引的設置。您應該在運行_reindex操作之前設置目標索引,包括設置映射、碎片計數、副本等。
# 復制源索引twitter到目標索引new_twitter POST _reindex { "source": { "index": "twitter" }, "dest": { "index": "new_twitter" } } 結果: { "took" : 1626, "timed_out" : false, "total" : 16, "updated" : 0, "created" : 16, "deleted" : 0, "batches" : 1, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] } # 查詢 GET /new_twitter/_search 結果: { "took" : 9, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 16, "max_score" : 1.0, "hits" : [ { "_index" : "new_twitter", "_type" : "t_doc", "_id" : "22", "_score" : 1.0, "_source" : { "user" : "Tony", "flag" : "1" } }, ... ] } }
為了避免出現沖突導致進程停止,指定:conflicts:proceed
POST _reindex { "conflicts": "proceed", "source": { "index": "twitter" }, "dest": { "index": "new_twitter", "op_type": "create" } }
還可以查詢出指定的內容,然后送進目標索引
POST _reindex { "source": { "index": "twitter", "type": "t_doc", "query": { "term": { "user": "kimchy" } } }, "dest": { "index": "new_twitter" } }
和可以合並多個索引到目標索引
#合並兩個索引,跳過沖突【conflicts】,只轉移10000條數據【size】 POST _reindex { "conflicts": "proceed", "size": 10000, "source": { "index": ["twitter", "new_twitter"], "type": ["t_doc", "post"] }, "dest": { "index": "all_together", "type": "all_doc" } }
還可以使用腳本、從遠程服務器reindex、修改目標字段名稱,請參考官方文檔
Java
/** * reIndex可用於將文檔從一個或多個索引復制到目標索引 * DocWriteRequest.OpType.CREATE 跳過已有的文檔 * DocWriteRequest.OpType.INDEX 已有相同id的會被覆蓋 * @return */ public static RestHighLevelClient reIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); ReindexRequest reindexRequest = new ReindexRequest() .setSourceIndices("twitter","new_twitter") .setDestIndex("all_together") .setDestOpType(DocWriteRequest.OpType.INDEX.getLowercase()) .setDestDocType("all_doc") // .setSize(10) // copy的文檔數 // .setScript(new Script(ScriptType.INLINE, "painless", // "if (ctx._source.user == 'kimchy') {ctx._source.likes++;}", // Collections.emptyMap())) // 腳本 .setSourceBatchSize(500); // 默認批量為1000,你可以自己設置批次獲取的數量 reindexRequest.setConflicts("proceed"); // 默認情況下,版本沖突會中止_reindex進程(abort) BulkByScrollResponse bulkResponse = client.reindex(reindexRequest, RequestOptions.DEFAULT); TimeValue timeTaken = bulkResponse.getTook(); boolean timedOut = bulkResponse.isTimedOut(); long totalDocs = bulkResponse.getTotal(); long updatedDocs = bulkResponse.getUpdated(); long createdDocs = bulkResponse.getCreated(); long deletedDocs = bulkResponse.getDeleted(); long batches = bulkResponse.getBatches(); long noops = bulkResponse.getNoops(); // 跳過的文檔數 long versionConflicts = bulkResponse.getVersionConflicts(); // 版本沖突的數量 long bulkRetries = bulkResponse.getBulkRetries(); // bulk重試次數 long searchRetries = bulkResponse.getSearchRetries(); // 搜索重試次數 System.out.println("花費時間:" + timeTaken + ",是否超時:" + timedOut + ",總文檔數:" + totalDocs + ",更新數:" + updatedDocs + ",創建數:" + createdDocs + ",刪除數:" + deletedDocs + ",批量次數:" + batches + ",跳過數:" + noops + ",沖突數:" + versionConflicts + ",bulk重試次數:" + bulkRetries + ",搜索重試次數:" + searchRetries); List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures(); // 搜索期間的故障 searchFailures.forEach(e -> { System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId()); }); List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures(); // 批量索引期間的故障 bulkFailures.forEach(e -> { System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId()); }); return client; }
因為這兩個索引內容一樣,所以會出現 更新數:16,創建數:16
花費時間:1.6s,是否超時:false,總文檔數:32,更新數:16,創建數:16,刪除數:0,批量次數:1,跳過數:0,沖突數:0,bulk重試次數:0,搜索重試次數:0
查看目標索引(總文檔數16)
GET /all_together/_search 結果: { "took" : 4, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 16, "max_score" : 1.0, "hits" : [ { "_index" : "all_together", "_type" : "all_doc", "_id" : "22", "_score" : 1.0, "_source" : { "user" : "Tony", "flag" : "1" } }, ... ] } }
--
11. Query
HTTP請求
RequestBodySearch 示例
# sort--mode:min、max、sum、avg、median # sort--order:asc、desc # 過濾_source:如果要禁用,"_source": false # Doc格式化:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-docvalue-fields.html # 高亮參數:寫在外面是全局的,寫在field里面是局部的 GET /_search { "query" : { "term" : { "user" : "Tony" } }, "_source": [ "obj1.*", "obj2.*" ], "from" : 0, "size" : 10, "sort" : [ {"price" : {"order" : "asc", "mode" : "avg"}} ], "script_fields" : { "my_field1" : { "script" : { "lang": "painless", "source": "doc['flag'].value * params.factor", "params" : { "factor" : 2.0 } } } }, "docvalue_fields" : [ { "field": "postDate", "format": "yyyy-MM-dd" } ], "highlight" : { "order" : "score", "pre_tags" : ["<tag1>"], "post_tags" : ["</tag1>"], "fields" : { "_all" : {}, "message" : {"fragment_size" : 150, "number_of_fragments" : 3} } } }
QueryDSL
**Match 與 Match Phrase【這里使用了ik分詞器】
# 准備測試數據 PUT test { "settings" : { "number_of_shards" : 1, "number_of_replicas" : 1 }, "mappings" : { "msg" : { "properties" : { "message" : { "type" : "text","analyzer": "ik_max_word" } } } } } PUT test/msg/100 {"message" : "她過山車一般的跌宕人生,成了 2018 年我聽過的最精彩、也最讓人感嘆唏噓的真人真事。"} PUT test/msg/101 {"message" : "她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。"} # match query GET /_search { "query": { "match" : { "message" : { "query" : "今天的主人公", "analyzer" : "ik_max_word" } } } } # Match Phrase Query 短語查詢 GET /_search { "query": { "match_phrase" : { "message" : { "query" : "今天的主人公", "analyzer" : "ik_max_word" } } } }
執行match的結果:
執行match phrase的結果
分詞器:
POST _analyze { "analyzer": "ik_max_word", "text": "今天的主人公" } --- { "tokens" : [ { "token" : "今天", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "的", "start_offset" : 2, "end_offset" : 3, "type" : "CN_CHAR", "position" : 1 }, { "token" : "主人公", "start_offset" : 3, "end_offset" : 6, "type" : "CN_WORD", "position" : 2 }, { "token" : "主人", "start_offset" : 3, "end_offset" : 5, "type" : "CN_WORD", "position" : 3 }, { "token" : "公", "start_offset" : 5, "end_offset" : 6, "type" : "CN_CHAR", "position" : 4 } ] }
結論:match會查出包含所有token的結果,而matchPhrase則只會查詢“今天的主人公”這一個詞組。
**Match Phrase Prefix Query,短語前綴查詢,顧名思義:以查詢關鍵字為前綴的查詢
# Match Phrase Prefix Query 短語前綴查詢 GET /_search { "query": { "match_phrase_prefix" : { "message" : { "query" : "她就是", "analyzer" : "ik_max_word" } } } } --- { "took" : 9, "timed_out" : false, "_shards" : { "total" : 28, "successful" : 28, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 3.2103658, "hits" : [ { "_index" : "test", "_type" : "msg", "_id" : "101", "_score" : 3.2103658, "_source" : { "message" : "她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。" } } ] } }
**Query String Query
# 字符串查詢 如果多個字段:"fields" : ["content", "name"] 代替default_field GET /_search { "query": { "query_string" : { "default_field" : "message", "query" : "(過山車) OR (伊麗莎白)" } } } --- { "took" : 5, "timed_out" : false, "_shards" : { "total" : 28, "successful" : 28, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 0.80259144, "hits" : [ { "_index" : "test", "_type" : "msg", "_id" : "101", "_score" : 0.80259144, "_source" : { "message" : "她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。" } }, { "_index" : "test", "_type" : "msg", "_id" : "100", "_score" : 0.6099695, "_source" : { "message" : "她過山車一般的跌宕人生,成了 2018 年我聽過的最精彩、也最讓人感嘆唏噓的真人真事。" } } ] } }
以下查詢的字段類型都為keyword,適合精確查詢
**TermQuery
# Term Query 適合關鍵字的查詢,字段類型為keyword GET /_search { "query": { "term": { "exact_value": "Quick Foxes!" } } }
**Terms Query
# Terms Query 對同一個字段匹配多個關鍵字 GET /_search { "query": { "terms" : { "user" : ["kimchy", "elasticsearch"]} } }
**Range Query
# Range Query 范圍查詢【gt:大於,gte:大於等於,lt:小於,lte:小於等於】 GET _search { "query": { "range" : { "age" : { "gte" : 10, "lte" : 20, "boost" : 2.0 } } } } # Range Query 日期【y-年,M-月,w-周,d-日,h-小時,H-小時,m-分鍾,s-秒。+1h:+1小時,-1d:-1天,/d:四舍五入到最近的日期,now:當前時間】比如:now = 2018-12-23 17:17:00 now/d = 2018-12-24 00:00:00 GET _search { "query": { "range" : { "date" : { "gte" : "now-1d/d", "lt" : "now/d" } } } } GET _search { "query": { "range" : { "birthday" : { "gte": "01/01/2012", "lte": "2013", "format": "dd/MM/yyyy||yyyy" } } } }
**Exists Query
# Exist Query 返回在原始字段 message 中至少有一個非空值的文檔 GET /_search { "query": { "exists" : { "field" : "message" } } }
**Prefix Query
# Prefix Query 前綴查詢 GET /_search { "query": { "prefix" : { "user" : "ki" } } }
**Wildcard Query
# Wildcard Query 不建議以通配符開頭,因為那樣性能最低 GET /_search { "query": { "wildcard" : { "user" : "ki*y" } } }
**Regexp Query
# Regexp Query 正則查詢,你可以使用任何正則表達式,同樣不建議以通配符開頭 GET /_search { "query": { "regexp":{ "name.first": "s.*y" } } }
**Fuzzy Query
# Fuzzy Query 模糊查詢【與SQL的模糊查詢不一樣,更多信息請自行查閱資料】 GET /_search { "query": { "fuzzy" : { "user" : "ki" } } }
**Type Query
# Type Query 查詢type下的所有文檔 GET /_search { "query": { "type" : { "value" : "t_doc" } } }
**Ids Query
# Ids Query 根據id列表查詢 GET /_search { "query": { "ids" : { "type" : "t_doc", "values" : ["1", "4", "100"] } } }
下面是復合查詢
# bool查詢【它有must、filter、should、must_not四個可選條件】 POST _search { "query": { "bool" : { "must" : { "term" : { "user" : "kimchy" } }, "filter": { "term" : { "tag" : "tech" } }, "must_not" : { "range" : { "age" : { "gte" : 10, "lte" : 20 } } }, "should" : [ { "term" : { "tag" : "wow" } }, { "term" : { "tag" : "elasticsearch" } } ], "minimum_should_match" : 1, "boost" : 1.0 } } }
下面是地理查詢,初始化數據 參見 19.2 geo_bounding_box查詢 地圖選點:這里
**地理邊界查詢【根據兩個點確定的矩形,查詢落在矩形內的坐標】
# 地理邊界查詢 GET /china_index/_search { "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_bounding_box" : { "location" : { "top_left" : "23.1706638271,113.0383300781", "bottom_right" : "22.9760953044,113.5025024414" } } } } } }
結果:
**地理半徑查詢【根據指定的坐標為中心,查詢半徑范圍內的坐標】
# 地理半徑查詢 GET /china_index/_search { "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_distance" : { "distance" : "20km", "location" : { "lat" : 39.6733703918, "lon" : 116.4111328125 } } } } } } --- { "took" : 6, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 1.0, "hits" : [ { "_index" : "china_index", "_type" : "city", "_id" : "150", "_score" : 1.0, "_source" : { "pName" : "北京市", "cName" : "大興區", "location" : { "lat" : 39.72684, "lon" : 116.34159 } } } ] } }
**地理多邊形查詢【查找指定的坐標圍成的多邊形內的坐標】
# 地理多邊形查詢 GET /china_index/_search { "query": { "bool" : { "must" : { "match_all" : {} }, "filter" : { "geo_polygon" : { "location" : { "points" : [ "20.4270128143,110.2807617188", "19.6632802200,109.7094726563", "19.6839702359,110.8520507813" ] } } } } } } --- { "took" : 39, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 4, "max_score" : 1.0, "hits" : [ { "_index" : "china_index", "_type" : "city", "_id" : "1555", "_score" : 1.0, "_source" : { "pName" : "海南省", "cName" : "海口", "location" : { "lat" : 20.02, "lon" : 110.35 } } }, { "_index" : "china_index", "_type" : "city", "_id" : "1556", "_score" : 1.0, "_source" : { "pName" : "海南省", "cName" : "瓊山", "location" : { "lat" : 19.98, "lon" : 110.33 } } }, { "_index" : "china_index", "_type" : "city", "_id" : "1558", "_score" : 1.0, "_source" : { "pName" : "海南省", "cName" : "定安", "location" : { "lat" : 19.68, "lon" : 110.31 } } }, { "_index" : "china_index", "_type" : "city", "_id" : "1562", "_score" : 1.0, "_source" : { "pName" : "海南省", "cName" : "澄邁", "location" : { "lat" : 19.75, "lon" : 110.0 } } } ] } }
**地理形狀查詢 geo_shape【這個資料比較少,所以我重點研究了一下】
# 存儲地理形狀的索引 # tree參數:geohash和quadtree,默認geohash # strategy參數:recursive和term,默認recursive【支持查詢:INTERSECTS,DISJOINT,WITHIN,CONTAINS】 # precision參數:精度,單位有in, inch, yd, yard, mi, miles, km, kilometers, m,meters, cm,centimeters, mm, millimeters # 形狀類型解釋 | GeoJSON Type | WKT Type | Elasticsearch Type # 單個地理坐標 Point POINT point # 給出兩個或多個點的任意一條線 LineString LINESTRING linestring # 閉合的多邊形,第一個和最后一個點必須匹配 Polygon POLYGON polygon # 一系列未連接但可能相關的點 MultiPoint MULTIPOINT multipoint # 一系列獨立的線 MultiLineString MULTILINESTRING multilinestring # 一系列單獨的多邊形 MultiPolygon MULTIPOLYGON multipolygon # 類似於multi系列,但是多種類型不可以共存 GeometryCollection GEOMETRYCOLLECTION geometrycollection # 僅指定左上角和右下角的矩形 無 BBOX envelope # 指定中心和半徑的圓,默認單位是米 無 無 circle PUT china_shape_index { "settings" : { "number_of_shards" : 1, "number_of_replicas" : 1 }, "mappings" : { "info" : { "properties" : { "remark" : { "type" : "keyword" }, "location" : { "type" : "geo_shape", "tree" : "geohash", "precision": "100m" } } } } }
添加不同類型的數據
# 注意,如果是數組[經度,緯度] # 添加一個點 POST /china_shape_index/info { "location" : { "type" : "point", "coordinates" : [109.1162109375,37.2653099556] } } # 添加一條線 POST /china_shape_index/info { "location" : { "type" : "linestring", "coordinates" : [[109.1162109375,37.2653099556], [117.6855468750,35.5322262277]] } } # 添加一個形狀【我畫了個三角形】 POST /china_shape_index/info { "location" : { "type" : "polygon", "coordinates" : [ [ [114.0380859375, 31.9148675033], [116.6748046875, 30.0690939644], [111.4453125000,29.7643773752], [114.0380859375, 31.9148675033] ] ] } } # 多個坐標 POST /china_shape_index/info { "location" : { "type" : "multipoint", "coordinates" : [ [111.4453125000,29.7643773752], [117.6855468750,35.5322262277] ] } } # 由leftTop和bottomRight圍成的矩形 POST /china_shape_index/info { "location" : { "type" : "envelope", "coordinates" : [ [120.2783203125,25.2049411536], [122.2119140625,23.4430889311] ] } } # 圓形 POST /china_shape_index/info { "location" : { "type" : "circle", "coordinates" : [116.5429687500,39.7071866568], "radius" : "10km" } }
形狀查詢【這里與我們測試數據(以北京為中心畫一個圓)相交了】
# 查詢相交的形狀。relation可選:intersects, disjoint, within, contains【相交,不相交,內部,包含】 GET /china_shape_index/_search { "query":{ "bool": { "must": { "match_all": {} }, "filter": { "geo_shape": { "location": { "shape": { "type": "envelope", "coordinates" : [[114.9169921875,40.5137991550], [118.6083984375,38.7883453551]] }, "relation": "intersects" } } } } } } --- { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 1.0, "hits" : [ { "_index" : "china_shape_index", "_type" : "info", "_id" : "FbvH82cBOwlg01SCD5ab", "_score" : 1.0, "_source" : { "location" : { "type" : "circle", "coordinates" : [ 116.54296875, 39.7071866568 ], "radius" : "10km" } } } ] } }
..
Java【太多了,我只選擇部分示例】
全文索引系列:matchQuery、matchAllQuery、matchPhraseQuery、matchPhrasePrefixQuery、multiMatchQuery、commonTermsQuery、queryStringQuery
Term系列:termQuery、termsQuery、rangeQuery、existsQuery、prefixQuery、wildcardQuery、regexpQuery、fuzzyQuery、typeQuery、idsQuery
地理系列:geoDistanceQuery、geoBoundingBoxQuery、geoPolygonQuery、geoShapeQuery
--
/** * matchQuery
* 排序,高亮查詢 * @return * @throws IOException */ public static RestHighLevelClient search() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); try { SearchResponse search = client.search(new SearchRequest("test") .source(new SearchSourceBuilder() .query(QueryBuilders.matchQuery("message", "今天的主人公")) .sort("_score", SortOrder.DESC) // 根據分數倒序排序 .from(0) // 返回結果開始位置 .size(5) // 返回結果數量 .timeout(TimeValue.timeValueSeconds(10)) // 超時 .highlighter(new HighlightBuilder() .field("message",200) .preTags("<pre>").postTags("</pre>")) ), RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println("分數:" + e.getScore() + ",結果:" + e.getSourceAsString()); Map<String, HighlightField> highlightFields = e.getHighlightFields(); for (String key : highlightFields.keySet()){ HighlightField field = highlightFields.get(key); System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/); } }); } catch (ElasticsearchException e) { if(e.status() == RestStatus.NOT_FOUND){ // TODO System.out.println("Index Not Found-" + e.getIndex()); } } return client; }
輸出:
Hits:2 分數:3.421475,結果:{"message":"她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。"} message:她就是我們<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊麗莎白·福爾摩斯(Elizabeth Holmes)。 分數:0.26740497,結果:{"message":"她過山車一般的跌宕人生,成了 2018 年我聽過的最精彩、也最讓人感嘆唏噓的真人真事。"} message:她過山車一般<pre>的</pre>跌宕人生,成了 2018 年我聽過<pre>的</pre>最精彩、也最讓人感嘆唏噓<pre>的</pre>真人真事。
--
/** * matchPhraseQuery * 排序,高亮查詢 * @return * @throws IOException */ public static RestHighLevelClient search() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); try { SearchResponse search = client.search(new SearchRequest("test") .source(new SearchSourceBuilder() .query(QueryBuilders.matchPhraseQuery("message", "今天的主人公")) .sort("_score", SortOrder.DESC) // 根據分數倒序排序 .from(0) // 返回結果開始位置 .size(5) // 返回結果數量 .timeout(TimeValue.timeValueSeconds(10)) // 超時 .highlighter(new HighlightBuilder() .field("message",200) .preTags("<pre>").postTags("</pre>")) ), RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println("分數:" + e.getScore() + ",結果:" + e.getSourceAsString()); Map<String, HighlightField> highlightFields = e.getHighlightFields(); for (String key : highlightFields.keySet()){ HighlightField field = highlightFields.get(key); System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/); } }); } catch (ElasticsearchException e) { if(e.status() == RestStatus.NOT_FOUND){ // TODO System.out.println("Index Not Found-" + e.getIndex()); } } return client; }
結果:
Hits:1 分數:3.421475,結果:{"message":"她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。"} message:她就是我們<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊麗莎白·福爾摩斯(Elizabeth Holmes)。
--
/** * queryStringQuery * 排序,高亮查詢 * @return * @throws IOException */ public static RestHighLevelClient search() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); try { SearchResponse search = client.search(new SearchRequest("test") .source(new SearchSourceBuilder() .query(QueryBuilders.queryStringQuery("今天的主人公").field("message")) .sort("_score", SortOrder.DESC) // 根據分數倒序排序 .from(0) // 返回結果開始位置 .size(5) // 返回結果數量 .timeout(TimeValue.timeValueSeconds(10)) // 超時 .highlighter(new HighlightBuilder() .field("message",200) .preTags("<pre>").postTags("</pre>")) ), RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println("分數:" + e.getScore() + ",結果:" + e.getSourceAsString()); Map<String, HighlightField> highlightFields = e.getHighlightFields(); for (String key : highlightFields.keySet()){ HighlightField field = highlightFields.get(key); System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/); } }); } catch (ElasticsearchException e) { if(e.status() == RestStatus.NOT_FOUND){ // TODO System.out.println("Index Not Found-" + e.getIndex()); } } return client; }
結果:
Hits:2 分數:3.421475,結果:{"message":"她就是我們今天的主人公,伊麗莎白·福爾摩斯(Elizabeth Holmes)。"} message:她就是我們<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊麗莎白·福爾摩斯(Elizabeth Holmes)。 分數:0.26740497,結果:{"message":"她過山車一般的跌宕人生,成了 2018 年我聽過的最精彩、也最讓人感嘆唏噓的真人真事。"} message:她過山車一般<pre>的</pre>跌宕人生,成了 2018 年我聽過<pre>的</pre>最精彩、也最讓人感嘆唏噓<pre>的</pre>真人真事。
下面測試term系列
# 准備測試數據 PUT users { "settings" : { "number_of_shards" : 1, "number_of_replicas" : 1 }, "mappings" : { "info" : { "properties" : { "username" : { "type" : "keyword" }, "address" : { "type" : "text","analyzer": "ik_max_word" } } } } } PUT users/info/1 {"username" : "孫行者","address" : "軟件產業基地1棟B座大堂","age": 15} PUT users/info/2 {"username" : "孫大聖","address" : "萬達北路710號戈雅公寓105號商鋪","age": 26} PUT users/info/3 {"username" : "西蒙·胡塞·德·拉·桑迪西瑪·特里尼達·玻利瓦爾·帕拉修斯·伊·布蘭科","address" : "濱河大道7009號","age": 7} PUT users/info/4 {"username" : "奧斯特洛夫斯基","address" : "光谷二路225號食堂","age": 30} PUT users/info/5 {"username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address" : "海淀紫竹院路甲2號商業05號","age": 18} # 查看 GET /users/_search
--
/** * termQuery * rangeQuery * prefixQuery * wildcardQuery * @return * @throws IOException */ public static RestHighLevelClient termSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("users"); String[] includeFields = new String[] {"username", "age"}; String[] excludeFields = new String[] {"addr*"}; request.source(new SearchSourceBuilder() // 關鍵字查詢 //.query(QueryBuilders.termsQuery("username", "奧斯特洛夫斯基")) // 范圍查詢 //.query(QueryBuilders.rangeQuery("age").lt(20)) // 前綴查詢 //.query(QueryBuilders.prefixQuery("username", "孫")) // 通配符查詢 .query(QueryBuilders.wildcardQuery("username", "西蒙*")) .fetchSource(includeFields, excludeFields) // 過濾源 .from(0) .size(5) .sort("age", SortOrder.ASC) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:1 {"age":7,"username":"西蒙·胡塞·德·拉·桑迪西瑪·特里尼達·玻利瓦爾·帕拉修斯·伊·布蘭科"}
下面測試聚合查詢 Aggregation
/** * 聚合查詢 * @return * @throws IOException */ public static RestHighLevelClient aggSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("users"); request.source(new SearchSourceBuilder() .query(QueryBuilders.matchAllQuery()) .aggregation(AggregationBuilders.avg("ageAVG").field("age")) .from(0) .size(5) .sort("age", SortOrder.ASC) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); Avg avg = search.getAggregations().get("ageAVG"); System.out.println("平均值:" + avg.getValue()); return client; }
結果:
Hits:5 {"username":"西蒙·胡塞·德·拉·桑迪西瑪·特里尼達·玻利瓦爾·帕拉修斯·伊·布蘭科","address":"濱河大道7009號","age":7} {"username":"孫行者","address":"軟件產業基地1棟B座大堂","age":15} {"username":"Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address":"海淀紫竹院路甲2號商業05號","age":18} {"username":"孫大聖","address":"萬達北路710號戈雅公寓105號商鋪","age":26} {"username":"奧斯特洛夫斯基","address":"光谷二路225號食堂","age":30} 平均值:19.2
下面測試復合查詢 bool
/** * 復合查詢 * @return * @throws IOException */ public static RestHighLevelClient boolSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("users"); request.source(new SearchSourceBuilder() .query(QueryBuilders.boolQuery() .must(QueryBuilders.rangeQuery("age").gt(20)) .mustNot(QueryBuilders.termQuery("username","孫大聖")) ) .from(0) .size(5) .sort("age", SortOrder.ASC) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:1 {"username":"奧斯特洛夫斯基","address":"光谷二路225號食堂","age":30}
下面測試地理查詢
--矩形
public static RestHighLevelClient geoSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("china_index"); request.source(new SearchSourceBuilder() // 地理邊界查詢,設置字段名,top Left和bottom Right .query(QueryBuilders.geoBoundingBoxQuery("location").setCorners(23.1706638271,113.0383300781,22.9760953044,113.5025024414)) .from(0) .size(100) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:9 {"pName":"廣東省","cName":"廣州","location":{"lat":23.12908,"lon":113.26436}} {"pName":"廣東省","cName":"越秀","location":{"lat":23.12901,"lon":113.2668}} {"pName":"廣東省","cName":"荔灣","location":{"lat":23.12586,"lon":113.24428}} {"pName":"廣東省","cName":"海珠","location":{"lat":23.08331,"lon":113.3172}} {"pName":"廣東省","cName":"天河","location":{"lat":23.12463,"lon":113.36199}} {"pName":"廣東省","cName":"白雲","location":{"lat":23.157032,"lon":113.273238}} {"pName":"廣東省","cName":"佛山","location":{"lat":23.02185,"lon":113.12192}} {"pName":"廣東省","cName":"禪城","location":{"lat":23.00944,"lon":113.12249}} {"pName":"廣東省","cName":"南海","location":{"lat":23.02882,"lon":113.14278}}
--圓形
public static RestHighLevelClient geoSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("china_index"); List<GeoPoint> list = new ArrayList<>(); list.add(new GeoPoint(20.4270128143,110.2807617188)); list.add(new GeoPoint(19.6632802200,109.7094726563)); list.add(new GeoPoint(19.6839702359,110.8520507813)); request.source(new SearchSourceBuilder() // 地理半徑查詢,設置字段名,緯度,經度,距離,距離類型 .query(QueryBuilders.geoDistanceQuery("location").point(39.6733703918,116.4111328125).distance(50, DistanceUnit.KILOMETERS)) .from(0) .size(100) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:15 {"pName":"北京市","cName":"東城區","location":{"lat":39.92855,"lon":116.41637}} {"pName":"北京市","cName":"西城區","location":{"lat":39.91231,"lon":116.36611}} {"pName":"北京市","cName":"朝陽區","location":{"lat":39.927289,"lon":116.4498}} {"pName":"北京市","cName":"豐台區","location":{"lat":39.85856,"lon":116.28616}} {"pName":"北京市","cName":"石景山區","location":{"lat":39.90569,"lon":116.22299}} {"pName":"北京市","cName":"海淀區","location":{"lat":39.95933,"lon":116.29845}} {"pName":"北京市","cName":"通州區","location":{"lat":39.916195,"lon":116.662852}} {"pName":"北京市","cName":"大興區","location":{"lat":39.72684,"lon":116.34159}} {"pName":"北京市","cName":"房山區","location":{"lat":39.74788,"lon":116.14294}} {"pName":"北京市","cName":"門頭溝區","location":{"lat":39.94048,"lon":116.10146}} {"pName":"河北省","cName":"涿縣","location":{"lat":39.48,"lon":115.98}} {"pName":"河北省","cName":"廊坊","location":{"lat":39.53,"lon":116.7}} {"pName":"河北省","cName":"安次","location":{"lat":39.52,"lon":116.69}} {"pName":"河北省","cName":"固安","location":{"lat":39.44,"lon":116.29}} {"pName":"河北省","cName":"永清","location":{"lat":39.32,"lon":116.48}}
--多邊形
public static RestHighLevelClient geoSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("china_index"); List<GeoPoint> list = new ArrayList<>(); list.add(new GeoPoint(20.4270128143,110.2807617188)); list.add(new GeoPoint(19.6632802200,109.7094726563)); list.add(new GeoPoint(19.6839702359,110.8520507813)); request.source(new SearchSourceBuilder() // 地理形狀查詢,設置字段名,圍成多邊形狀的坐標列表 .query(QueryBuilders.geoPolygonQuery("location", list)) .from(0) .size(100) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:4 {"pName":"海南省","cName":"海口","location":{"lat":20.02,"lon":110.35}} {"pName":"海南省","cName":"瓊山","location":{"lat":19.98,"lon":110.33}} {"pName":"海南省","cName":"定安","location":{"lat":19.68,"lon":110.31}} {"pName":"海南省","cName":"澄邁","location":{"lat":19.75,"lon":110.0}}
-- geo_shape查詢
/** * 地理形狀查詢 * https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html * 已知Builder實現:CircleBuilder, EnvelopeBuilder, GeometryCollectionBuilder, LineStringBuilder, MultiLineStringBuilder, MultiPointBuilder, MultiPolygonBuilder, PointBuilder, PolygonBuilder * @return * @throws IOException */ public static RestHighLevelClient geoShapeSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); SearchRequest request = new SearchRequest("china_shape_index"); request.source(new SearchSourceBuilder() .query(QueryBuilders.geoShapeQuery("location", // 查詢類型為envelope就用EnvelopeBuilder. topLeft,bottomRight. new Coordinate(經度,緯度) new EnvelopeBuilder(new Coordinate(114.9169921875,40.5137991550),new Coordinate(118.6083984375,38.7883453551))) .relation(ShapeRelation.INTERSECTS) ) // ShapeBuilders已經過時,不推薦使用了 //.query(QueryBuilders.geoShapeQuery("location",ShapeBuilders.newEnvelope(new Coordinate(114.9169921875,40.5137991550),new Coordinate(118.6083984375,38.7883453551)))) .from(0) .size(100) ); SearchResponse search = client.search(request, RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); return client; }
結果:
Hits:1 {"location":{"type":"circle","coordinates":[116.54296875,39.7071866568],"radius":"10km"}}
12. Search
**search scroll
/** * scrollSearch * @return * @throws IOException */ public static RestHighLevelClient scrollSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); // 設置超時 final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L)); SearchRequest request = new SearchRequest("books"); request.source(new SearchSourceBuilder() .query(QueryBuilders.matchAllQuery()) .sort("_id",SortOrder.ASC) .size(500)) // 每批大小 .scroll(scroll); // 設置scroll SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT); // 執行查詢 String scrollId = searchResponse.getScrollId(); SearchHit[] hits = searchResponse.getHits().getHits(); while(hits != null && hits.length > 0) { System.out.println("========Begin======="); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); } System.out.println("========End======="); System.out.println("Size:" + hits.length + ",Scroll:" + scrollId); SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId) .scroll(scroll); // 設置SearchScrollRequest searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT); // 拉取新的數據 scrollId = searchResponse.getScrollId(); hits = searchResponse.getHits().getHits(); }; // 當scroll超時時,Search Scroll API使用的搜索上下文將自動刪除 ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); clearScrollRequest.addScrollId(scrollId); ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); boolean succeeded = clearScrollResponse.isSucceeded(); System.out.println("ClearScroll:" + succeeded); return client; }
結果:【一共2000條,省略了部分結果】
========Begin======= {"title":"title_1","user":"user_1"} {"title":"title_10","user":"user_10"} {"title":"title_100","user":"user_100"} {"title":"title_1000","user":"user_1000"} ... {"title":"title_1448","user":"user_1448"} ========End======= Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB ========Begin======= ... {"title":"title_1899","user":"user_1899"} ========End======= Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB ========Begin======= {"title":"title_19","user":"user_19"} ... {"title":"title_548","user":"user_548"} ========End======= Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB ========Begin======= {"title":"title_549","user":"user_549"} ... {"title":"title_6","user":"user_6"} {"title":"title_60","user":"user_60"} {"title":"title_600","user":"user_600"} ... {"title":"title_699","user":"user_699"} {"title":"title_7","user":"user_7"} {"title":"title_70","user":"user_70"} {"title":"title_700","user":"user_700"} ... {"title":"title_799","user":"user_799"} {"title":"title_8","user":"user_8"} {"title":"title_80","user":"user_80"} {"title":"title_800","user":"user_800"} ... {"title":"title_899","user":"user_899"} {"title":"title_9","user":"user_9"} {"title":"title_90","user":"user_90"} {"title":"title_900","user":"user_900"} ... {"title":"title_999","user":"user_999"} ========End======= Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB ClearScroll:true
**Multi-Search
HTTP請求
# 格式:一行header一行body GET users/_msearch {} {"query": {"terms" : { "username" : ["孫行者", "孫大聖"]}}} {} {"query": {"term" : { "username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b"}}} --- { "responses" : [ { "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 1.0, "hits" : [ { "_index" : "users", "_type" : "info", "_id" : "1", "_score" : 1.0, "_source" : { "username" : "孫行者", "address" : "軟件產業基地1棟B座大堂", "age" : 15 } }, { "_index" : "users", "_type" : "info", "_id" : "2", "_score" : 1.0, "_source" : { "username" : "孫大聖", "address" : "萬達北路710號戈雅公寓105號商鋪", "age" : 26 } } ] }, "status" : 200 }, { "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 1.3862944, "hits" : [ { "_index" : "users", "_type" : "info", "_id" : "5", "_score" : 1.3862944, "_source" : { "username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b", "address" : "海淀紫竹院路甲2號商業05號", "age" : 18 } } ] }, "status" : 200 } ] }
Java
public static RestHighLevelClient multiSearch() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); MultiSearchRequest request = new MultiSearchRequest(); // 第一個查詢 SearchRequest firstSearchRequest = new SearchRequest("users"); firstSearchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termsQuery("username","孫大聖"))); request.add(firstSearchRequest); // 第二個查詢 SearchRequest secondSearchRequest = new SearchRequest("users"); secondSearchRequest.source(new SearchSourceBuilder().query(QueryBuilders.prefixQuery("username", "Brfxx"))); request.add(secondSearchRequest); MultiSearchResponse msearch = client.msearch(request, RequestOptions.DEFAULT); MultiSearchResponse.Item[] responses = msearch.getResponses(); for (MultiSearchResponse.Item i : responses){ System.out.println("========" + i.getResponse().status().name()); i.getResponse().getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); } return client; }
結果:
========OK {"username":"孫大聖","address":"萬達北路710號戈雅公寓105號商鋪","age":26} ========OK {"username":"Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address":"海淀紫竹院路甲2號商業05號","age":18}
13. Cluster
HTTP請求
GET _cluster/health --- { "cluster_name" : "my-elasticsearch", "status" : "yellow", "timed_out" : false, "number_of_nodes" : 1, "number_of_data_nodes" : 1, "active_primary_shards" : 15, "active_shards" : 15, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 14, "delayed_unassigned_shards" : 0, "number_of_pending_tasks" : 0, "number_of_in_flight_fetch" : 0, "task_max_waiting_in_queue_millis" : 0, "active_shards_percent_as_number" : 51.724137931034484 }
獲取集群狀態
GET /_cluster/state --- { "cluster_name" : "my-elasticsearch", "compressed_size_in_bytes" : 14766, "cluster_uuid" : "QmDZ773JR_ip0AN6jEdWtA", "version" : 33, "state_uuid" : "l8WJu9BzTfGsIKba_gsodA", "master_node" : "wCr6Uz0jTvGaTHh5acNxKA", "blocks" : { }, "nodes" : { "wCr6Uz0jTvGaTHh5acNxKA" : { "name" : "wCr6Uz0", "ephemeral_id" : "qFZoP0iWQDm3EWM3TDb_vg", "transport_address" : "127.0.0.1:9300", "attributes" : { "ml.machine_memory" : "8510087168", "xpack.installed" : "true", "ml.max_open_jobs" : "20", "ml.enabled" : "true" } } }, ... }
GET /_cluster/stats?human&pretty GET /_cluster/settings # 設置集群settings # 1. transient cluster settings # 2. persistent cluster settings # 3. settings in the elasticsearch.yml configuration file. PUT /_cluster/settings { "persistent" : { "indices.recovery.max_bytes_per_sec" : "50mb" } } # explain索引【三個參數必須的】 GET /_cluster/allocation/explain { "index": "china_index", "shard": 0, "primary": true } # 節點統計數據 GET /_nodes/stats GET /_nodes/nodeId1,nodeId2/stats # return just indices GET /_nodes/stats/indices # return just os and process GET /_nodes/stats/os,process # return just process for node with IP address 10.0.0.1 GET /_nodes/10.0.0.1/stats/process # 每個節點的實用信息 GET _nodes/usage GET _nodes/nodeId1,nodeId2/usage
Java
/** * 集群信息 * @return */ public static RestHighLevelClient info() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); boolean ping = client.ping(RequestOptions.DEFAULT); System.out.println("Ping:" + ping); MainResponse info = client.info(RequestOptions.DEFAULT); ClusterName clusterName = info.getClusterName(); String clusterUuid = info.getClusterUuid(); String nodeName = info.getNodeName(); Version version = info.getVersion(); Build build = info.getBuild(); System.out.println("集群名稱:" + clusterName.value()); System.out.println("Uuid:" + clusterUuid); System.out.println("節點名稱:" + nodeName); System.out.println("Version:" + version.toString()); System.out.println("Bulid:" + build.toString()); return client; }
結果:
Ping:true 集群名稱:my-elasticsearch Uuid:QmDZ773JR_ip0AN6jEdWtA 節點名稱:wCr6Uz0 Version:6.5.0 Bulid:[default][zip][816e6f6][2018-11-09T18:58:36.352602Z]
14. Indices
14.1 分詞器
# 標准分詞器 GET _analyze { "analyzer" : "standard", "text" : ["this is a test", "the second text"] } # IK分詞器 GET _analyze { "analyzer" : "ik_smart", "text" : ["真好玩", "一個叫yado的博士找到他,希望buzzo和他的團伙去幫他散布一種叫做joy的毒品"] }
--
/** * 分詞器 * @return * @throws IOException */ public static RestHighLevelClient analyze() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); AnalyzeRequest request = new AnalyzeRequest(); request.text("真好玩", "一個叫yado的博士找到他,希望buzzo和他的團伙去幫他散布一種叫做joy的毒品"); request.analyzer("ik_smart"); AnalyzeResponse response = client.indices().analyze(request, RequestOptions.DEFAULT); List<AnalyzeResponse.AnalyzeToken> tokens = response.getTokens(); for(AnalyzeResponse.AnalyzeToken t : tokens){ int endOffset = t.getEndOffset(); int position = t.getPosition(); int positionLength = t.getPositionLength(); int startOffset = t.getStartOffset(); String term = t.getTerm(); String type = t.getType(); System.out.println("Start:" + startOffset + ",End:" + endOffset + ",Position:" + position + ",Length:" + positionLength + ",Term:" + term + ",Type:" + type); } return client; }
結果:
Start:0,End:3,Position:0,Length:1,Term:真好玩,Type:CN_WORD Start:4,End:6,Position:1,Length:1,Term:一個,Type:CN_WORD Start:6,End:7,Position:2,Length:1,Term:叫,Type:CN_CHAR Start:7,End:11,Position:3,Length:1,Term:yado,Type:ENGLISH Start:11,End:12,Position:4,Length:1,Term:的,Type:CN_CHAR Start:12,End:14,Position:5,Length:1,Term:博士,Type:CN_WORD Start:14,End:15,Position:6,Length:1,Term:找,Type:CN_CHAR Start:15,End:17,Position:7,Length:1,Term:到他,Type:CN_WORD Start:18,End:20,Position:8,Length:1,Term:希望,Type:CN_WORD Start:20,End:25,Position:9,Length:1,Term:buzzo,Type:ENGLISH Start:25,End:27,Position:10,Length:1,Term:和他,Type:CN_WORD Start:27,End:28,Position:11,Length:1,Term:的,Type:CN_CHAR Start:28,End:30,Position:12,Length:1,Term:團伙,Type:CN_WORD Start:30,End:31,Position:13,Length:1,Term:去,Type:CN_CHAR Start:31,End:32,Position:14,Length:1,Term:幫,Type:CN_CHAR Start:32,End:33,Position:15,Length:1,Term:他,Type:CN_CHAR Start:33,End:35,Position:16,Length:1,Term:散布,Type:CN_WORD Start:35,End:37,Position:17,Length:1,Term:一種,Type:CN_WORD Start:37,End:39,Position:18,Length:1,Term:叫做,Type:CN_WORD Start:39,End:42,Position:19,Length:1,Term:joy,Type:ENGLISH Start:42,End:43,Position:20,Length:1,Term:的,Type:CN_CHAR Start:43,End:45,Position:21,Length:1,Term:毒品,Type:CN_WORD
14.2 Create Index
創建索引限制
小寫字母 不能包含 \, /, *, ?, ", <, >, |, ` ` (space character), ,, # 7.0之前的索引可能包含冒號(:),但是不贊成這樣做,7.0+不支持這樣做 不能以-,_,+開頭 不能. or .. 長度不能超過255字節
HTTP請求
# 創建索引 PUT twitter { "settings" : { "number_of_shards" : 3, "number_of_replicas" : 2 }, "mappings" : { "my_doc" : { "properties" : { "field1" : { "type" : "text" } } } } }
Java
public static RestHighLevelClient createIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); CreateIndexRequest request = new CreateIndexRequest("twitter"); request.settings(Settings.builder() .put("index.number_of_shards", 3) .put("index.number_of_replicas", 2)) // 設置mapping //.mapping("t_doc", "field1","type=keyword,store=true") // Object key-pairs .mapping("t_doc", jsonBuilder() .startObject() .startObject("t_doc") .startObject("properties") .startObject("msg") .field("type","text") .endObject() .endObject() .endObject() .endObject()) // 別名 .alias(new Alias("my_index_alias")) // 創建超時 .timeout(TimeValue.timeValueMinutes(2)) // 連接到主節點超時時間 .masterNodeTimeout(TimeValue.timeValueMinutes(1)) // 在創建索引返回響應之前等待的活動碎片副本的數量 .waitForActiveShards(2); CreateIndexResponse indexResponse = client.indices().create(request, RequestOptions.DEFAULT); boolean acknowledged = indexResponse.isAcknowledged(); boolean shardsAcknowledged = indexResponse.isShardsAcknowledged(); System.out.println(acknowledged); return client; }
14.3 Delete Index
# 刪除索引
DELETE /twitter
Java
public static RestHighLevelClient deleteIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); DeleteIndexRequest request = new DeleteIndexRequest(); // 使用_all或者通配符*可以刪除所有索引。如果要禁用:action.destructive_requires_name=true request.indices("twitter","it_book","car","school","story"); try { AcknowledgedResponse acknowledgedResponse = client.indices().delete(request, RequestOptions.DEFAULT); boolean acknowledged = acknowledgedResponse.isAcknowledged(); System.out.println(acknowledged); } catch (ElasticsearchException exception) { if (exception.status() == RestStatus.NOT_FOUND) { System.err.println("Index Not Found"); } } return client; }
14.4 Indices Exists
# 索引是否存在 HEAD /china_index # Type是否存在 HEAD /china_index/_mapping/city
Java
public static RestHighLevelClient existIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetIndexRequest request = new GetIndexRequest(); request.indices("china_index"); boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); System.out.println(exists); return client; }
14.5 Open Index
# 開啟索引
POST /twitter/_open
Java
public static RestHighLevelClient openIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); OpenIndexRequest request = new OpenIndexRequest("twitter"); request.timeout(TimeValue.timeValueMinutes(2)); OpenIndexResponse open = client.indices().open(request, RequestOptions.DEFAULT); boolean acknowledged = open.isAcknowledged(); boolean shardsAcked = open.isShardsAcknowledged(); System.out.println(acknowledged); return client; }
14.6 Close Index
# 關閉索引
POST /twitter/_close
Java
public static RestHighLevelClient closeIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); CloseIndexRequest request = new CloseIndexRequest("twitter"); request.timeout(TimeValue.timeValueMinutes(2)); AcknowledgedResponse closeIndexResponse = client.indices().close(request, RequestOptions.DEFAULT); boolean acknowledged = closeIndexResponse.isAcknowledged(); System.out.println(acknowledged); return client; }
14.7 Shrink Index【壓縮索引】
# 准備源索引 PUT my_source_index { "settings" : { "number_of_shards" : 4, "number_of_replicas" : 2, "index.blocks.write": true } } -- { "acknowledged" : true, "shards_acknowledged" : true, "index" : "my_source_index" }
壓縮操作
POST my_source_index/_shrink/my_target_index?copy_settings=true { "settings": { "index.number_of_shards": 1, "index.number_of_replicas": 1, "index.codec": "best_compression" }, "aliases": { "my_search_indices": {} } } -- { "acknowledged" : true, "shards_acknowledged" : true, "index" : "my_target_index" }
查看索引信息
GET my_source_index 結果: { "my_source_index" : { "aliases" : { }, "mappings" : { }, "settings" : { "index" : { "number_of_shards" : "4", "blocks" : { "write" : "true" }, "provided_name" : "my_source_index", "creation_date" : "1546589291669", "number_of_replicas" : "2", "uuid" : "tSYNLldWQNCOlR5NJGaH9g", "version" : { "created" : "6050099" } } } } } --- GET my_target_index 結果: { "my_target_index" : { "aliases" : { "my_search_indices" : { } }, "mappings" : { }, "settings" : { "index" : { "allocation" : { "max_retries" : "1" }, "shrink" : { "source" : { "name" : "my_source_index", "uuid" : "tSYNLldWQNCOlR5NJGaH9g" } }, "blocks" : { "write" : "true" }, "provided_name" : "my_target_index", "creation_date" : "1546589354014", "number_of_replicas" : "1", "uuid" : "F976xviGQ965JU9patwQnA", "version" : { "created" : "6050099", "upgraded" : "6050099" }, "codec" : "best_compression", "routing" : { "allocation" : { "initial_recovery" : { "_id" : "wCr6Uz0jTvGaTHh5acNxKA" } } }, "number_of_shards" : "1", "routing_partition_size" : "1", "resize" : { "source" : { "name" : "my_source_index", "uuid" : "tSYNLldWQNCOlR5NJGaH9g" } } } } } }
Java
/** * 壓縮索引(將索引壓縮為主分片數更少的新索引) * 目標索引中請求的主碎片數量必須是源索引中碎片數量的一個因數。例如,有8個主碎片的索引可以壓縮為4個、2個或1個主碎片; * 或者有15個主碎片的索引可以壓縮為5個、3個或1個主碎片。 * 過程: * 首先,它創建一個新的目標索引,其定義與源索引相同,但是主碎片的數量較少 * 然后它將段從源索引硬鏈接到目標索引 * 最后,它將目標索引恢復為一個剛剛重新打開的closed index * @return */ public static RestHighLevelClient shrinkIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); ResizeRequest resizeRequest = new ResizeRequest("target_index", "source_index"); resizeRequest.getTargetIndexRequest() .alias(new Alias("target_index_alias")) .settings(Settings.builder() .put("index.number_of_shards", 2) ); ResizeResponse resizeResponse = client.indices().shrink(resizeRequest, RequestOptions.DEFAULT); boolean acknowledged = resizeResponse.isAcknowledged(); boolean shardsAcked = resizeResponse.isShardsAcknowledged(); System.out.println(acknowledged); return client; }
14.8 Split Index
准備數據
# index.number_of_routing_shards must be >= index.number_of_shards PUT my_source_index2 { "settings" : { "number_of_shards" : 2, "index.number_of_routing_shards" : 8, "index.blocks.write": true } } -- { "acknowledged" : true, "shards_acknowledged" : true, "index" : "my_source_index2" }
拆分
# 拆分索引 POST my_source_index2/_split/my_target_index2?copy_settings=true { "settings": { "index.number_of_shards": 4 }, "aliases": { "my_search_indices": {} } } -- { "acknowledged" : true, "shards_acknowledged" : true, "index" : "my_target_index2" }
查看索引
GET my_source_index2 結果: { "my_source_index2" : { "aliases" : { }, "mappings" : { }, "settings" : { "index" : { "number_of_shards" : "2", "blocks" : { "write" : "true" }, "provided_name" : "my_source_index2", "creation_date" : "1546590226265", "number_of_replicas" : "1", "uuid" : "iuDENl3uQku0Ef6flu8S-Q", "version" : { "created" : "6050099" } } } } } --- GET my_target_index2 結果: { "my_target_index2" : { "aliases" : { "my_search_indices" : { } }, "mappings" : { }, "settings" : { "index" : { "number_of_shards" : "4", "routing_partition_size" : "1", "blocks" : { "write" : "true" }, "provided_name" : "my_target_index2", "resize" : { "source" : { "name" : "my_source_index2", "uuid" : "iuDENl3uQku0Ef6flu8S-Q" } }, "creation_date" : "1546590255143", "number_of_replicas" : "1", "uuid" : "ZBnocs2bSker45kb2lXoRw", "version" : { "created" : "6050099", "upgraded" : "6050099" } } } } }
Java
/** * 拆分索引(每個原始的主碎片被拆分為新索引中的兩個或多個主碎片) * 重要:源索引必須在創建的時候指定number_of_routing_shards參數,以便將來有拆分的需要。在Elasticsearch 7.0這個前提被移除。 * 索引能被拆分的次數以及每個主分片能被拆分的個數取決於index.number_of_routing_shards參數的設置 * 過程: * 首先,它創建一個新的目標索引,其定義與源索引相同,但是具有更多的主碎片 * 然后它將段從源索引硬鏈接到目標索引 * 創建了低級文件之后,所有文檔將再次散列以刪除屬於不同碎片的文檔 * 最后,它將目標索引恢復為一個剛剛重新打開的closed index * @return */ public static RestHighLevelClient splitIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); ResizeRequest resizeRequest = new ResizeRequest("target_index", "source_index"); resizeRequest.timeout(TimeValue.timeValueSeconds(2)) .masterNodeTimeout(TimeValue.timeValueMinutes(1)) .setResizeType(ResizeType.SPLIT); // 類型是拆分 resizeRequest.getTargetIndexRequest() .alias(new Alias("target_index_alias")) .settings(Settings.builder() .put("index.number_of_shards", 4)); ResizeResponse resizeResponse = client.indices().split(resizeRequest, RequestOptions.DEFAULT); boolean acknowledged = resizeResponse.isAcknowledged(); boolean shardsAcked = resizeResponse.isShardsAcknowledged(); return client; }
14.9 Refresh
# 刷新索引【默認定期刷新】 POST /kimchy,elasticsearch/_refresh POST /_refresh
--
/** * 刷新索引 * 默認情況下,刷新是定期調度的 * @return */ public static RestHighLevelClient refreshIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); RefreshRequest refreshRequest = new RefreshRequest("index_1","index_2"); try { RefreshResponse refresh = client.indices().refresh(refreshRequest, RequestOptions.DEFAULT); int totalShards = refresh.getTotalShards(); int successfulShards = refresh.getSuccessfulShards(); int failedShards = refresh.getFailedShards(); DefaultShardOperationFailedException[] failures = refresh.getShardFailures(); } catch (ElasticsearchException exception) { if (exception.status() == RestStatus.NOT_FOUND) { // TODO } } return client; }
14.10 Flush
POST twitter/_flush
---
/** * https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-flush.html * 索引的刷新進程通過將數據刷新到索引存儲並清除內部事務日志,基本上將內存從索引中釋放出來 * @return * @throws IOException */ public static RestHighLevelClient flushIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); FlushRequest requestMultiple = new FlushRequest("index1", "index2"); try { FlushResponse flushResponse = client.indices().flush(requestMultiple, RequestOptions.DEFAULT); int totalShards = flushResponse.getTotalShards(); int successfulShards = flushResponse.getSuccessfulShards(); int failedShards = flushResponse.getFailedShards(); DefaultShardOperationFailedException[] failures = flushResponse.getShardFailures(); } catch (ElasticsearchException exception) { if (exception.status() == RestStatus.NOT_FOUND) { // TODO } } return client; }
14.11 Clear Cache
# 清空緩存
POST /twitter/_cache/clear
---
/** * 清除索引的緩存 * @return */ public static RestHighLevelClient clearCacheIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); ClearIndicesCacheRequest cacheRequest = new ClearIndicesCacheRequest("index1", "index2"); cacheRequest.queryCache(true); // 查詢 cacheRequest.fieldDataCache(true); // 字段數據 cacheRequest.requestCache(true); // 請求 cacheRequest.fields("field1", "field2", "field3"); try { ClearIndicesCacheResponse clearCache = client.indices().clearCache(cacheRequest, RequestOptions.DEFAULT); int totalShards = clearCache.getTotalShards(); int successfulShards = clearCache.getSuccessfulShards(); int failedShards = clearCache.getFailedShards(); DefaultShardOperationFailedException[] failures = clearCache.getShardFailures(); } catch (ElasticsearchException exception) { if (exception.status() == RestStatus.NOT_FOUND) { // TODO } } return client; }
14.12 Force Merge
Http
# 合並 POST /kimchy/_forcemerge?only_expunge_deletes=false&max_num_segments=100&flush=true # max_num_segments=1,所有的段都重寫為一個新的 POST /kimchy,elasticsearch/_forcemerge
Java
/** * 合並一個或多個索引 * 此調用將阻塞,直到合並完成。如果http連接丟失,請求將在后台繼續,任何新請求都將阻塞,直到前一個強制合並完成 * **強制合並只能對只讀索引調用。對讀寫索引執行強制合並會導致產生非常大的段(每段大於5GB) * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-force-merge.html * https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html * @return */ public static RestHighLevelClient ForceMergeIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); ForceMergeRequest requestMultiple = new ForceMergeRequest("index1", "index2"); // 要合並的分片數。要完全合並索引,請將其設置為1 requestMultiple.maxNumSegments(1); // 合並過程是否刪除標記為刪除的段。在Lucene中,一個文檔不是從一個段中刪除,而是標記為已刪除。在段的合並過程中,將創建一個沒有這些刪除的新段。 // 此標志只允許合並具有刪除的段。默認值為false requestMultiple.onlyExpungeDeletes(true); requestMultiple.flush(true); try { ForceMergeResponse forceMergeResponse = client.indices().forcemerge(requestMultiple, RequestOptions.DEFAULT); int totalShards = forceMergeResponse.getTotalShards(); int successfulShards = forceMergeResponse.getSuccessfulShards(); int failedShards = forceMergeResponse.getFailedShards(); DefaultShardOperationFailedException[] failures = forceMergeResponse.getShardFailures(); } catch (ElasticsearchException exception) { if (exception.status() == RestStatus.NOT_FOUND) { // TODO } } return client; }
14.13 Put Mapping
HTTP
# 增加一個不帶type的索引 PUT twitter {} # 增加type PUT twitter/_mapping/_doc { "properties": { "email": { "type": "keyword" } } }
Java
/** * 添加mapping(不能更新已存在的字段類型) * @return */ public static RestHighLevelClient putMapping() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); PutMappingRequest request = new PutMappingRequest("twitter"); request.type("_doc"); // 我更喜歡Object key-pairs 的形式 request.source("message","type=text","name","type=keyword"); request.timeout(TimeValue.timeValueMinutes(2)); request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); AcknowledgedResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT); boolean acknowledged = putMappingResponse.isAcknowledged(); System.out.println(acknowledged); return client; }
14.14 Get Mappings
HTTP
# 獲取全部索引的Mapping,可以精確到type GET /_all/_mapping/[Type] #獲取指定索引的Mapping GET /twitter/_mapping/[Type] # 例如: GET /china_index/_mapping ... { "china_index" : { "mappings" : { "city" : { "properties" : { "cName" : { "type" : "text" }, "location" : { "type" : "geo_point" }, "pName" : { "type" : "keyword" } } } } } }
Java
/** * 獲取mapping * @return * @throws IOException */ public static RestHighLevelClient getMapping() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetMappingsRequest request = new GetMappingsRequest(); request.indices("china_index"); request.types("city"); request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); GetMappingsResponse getMappingResponse = client.indices().getMapping(request, RequestOptions.DEFAULT); getMappingResponse.getMappings().forEach(e -> { String key = e.key; ImmutableOpenMap<String, MappingMetaData> value = e.value; value.forEach(v -> { System.out.println(key + "|" + v.key + "|" + v.value.getSourceAsMap()); }); }); return client; }
結果:
china_index|city|{properties={pName={type=keyword}, cName={type=text}, location={type=geo_point}}}
14.15 Get Field Mappings
HTTP
# 查看具體字段的Mapping信息 GET [索引]/_mapping/field/[field1,field2] GET china_index/_mapping/field/pName,location .. { "china_index" : { "mappings" : { "city" : { "pName" : { "full_name" : "pName", "mapping" : { "pName" : { "type" : "keyword" } } }, "location" : { "full_name" : "location", "mapping" : { "location" : { "type" : "geo_point" } } } } } } }
Java
/** * 獲取指定字段的Mapping * @return * @throws IOException */ public static RestHighLevelClient getFieldMappings() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetFieldMappingsRequest request = new GetFieldMappingsRequest(); request.indices("china_index"); // 可以多個索引 request.types("city"); // 多個類型 request.fields("pName","location"); // 多個字段 GetFieldMappingsResponse response = client.indices().getFieldMapping(request, RequestOptions.DEFAULT); Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings = response.mappings(); mappings.keySet().forEach(e -> { Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>> mapMap = mappings.get(e); mapMap.keySet().forEach(i -> { Map<String, GetFieldMappingsResponse.FieldMappingMetaData> metaDataMap = mapMap.get(i); metaDataMap.keySet().forEach(j -> { GetFieldMappingsResponse.FieldMappingMetaData fieldMappingMetaData = metaDataMap.get(j); System.out.println(e + "|" + i + "|" + j + "|" + fieldMappingMetaData.sourceAsMap()); }); }); }); return client; }
結果:
china_index|city|pName|{pName={type=keyword}} china_index|city|location|{location={type=geo_point}}
14.16 Index Aliases
HTTP
# 添加別名 POST /_aliases { "actions" : [ { "remove" : { "index" : "test1", "alias" : "alias1" } }, { "add" : { "index" : "test2", "alias" : "alias1" } } ] } # 例子 POST /_aliases { "actions" : [ { "add" : { "index" : "my_source_index", "alias" : "alias111" } }, { "add" : { "index" : "my_source_index2", "alias" : "alias222" } } ] } ... { "acknowledged" : true }
Java
/** * 添加別名,這個方法只是列出了一些情況,如果要運行請先根據實際情況修改 * @return */ public static RestHighLevelClient indexAlias() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); IndicesAliasesRequest request = new IndicesAliasesRequest(); IndicesAliasesRequest.AliasActions aliasAction = new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD) .index("index1") .alias("alias1"); // 添加別名,並指定routing IndicesAliasesRequest.AliasActions addIndicesAction = new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD) .indices("index1", "index2") .alias("alias2") .routing("my_routing"); // 移除別名 IndicesAliasesRequest.AliasActions removeAction = new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE) .index("index3") .alias("alias3"); // 刪除索引 IndicesAliasesRequest.AliasActions removeIndexAction = new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE_INDEX) .index("index4"); request.addAliasAction(aliasAction); AcknowledgedResponse indicesAliasesResponse = client.indices().updateAliases(request, RequestOptions.DEFAULT); boolean acknowledged = indicesAliasesResponse.isAcknowledged(); System.out.println(acknowledged); return client; }
14.17 Exists Alias
HTTP
# 檢查 HEAD /my_source_index/_alias/alias111 # 從所有索引里面找別名為2016的 HEAD /_alias/2016 # 還可以使用通配符 HEAD /_alias/20* --- 存在的話 200 - OK 不存在 404 - Not Found
Java
/** * 判斷別名是否存在 * @return * @throws IOException */ public static RestHighLevelClient aliasExist() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetAliasesRequest request = new GetAliasesRequest(); request.aliases("alias222"); request.indices("my_source_index2"); // GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1"); // 單個 // GetAliasesRequest requestWithAliases = // new GetAliasesRequest(new String[]{"alias1", "alias2"}); // 多個 boolean exists = client.indices().existsAlias(request, RequestOptions.DEFAULT); System.out.println(exists); return client; }
結果:true
14.18 Get Alias
HTTP
# 獲取 GET /my_source_index/_alias/alias111 -- { "my_source_index" : { "aliases" : { "alias111" : { } } } } # 從所有索引里面找別名為alias222的 GET /_alias/alias222 -- { "my_source_index2" : { "aliases" : { "alias222" : { } } } } # 還可以使用通配符 GET /_alias/20* # 顯示索引的所有別名 GET /my_source_index/_alias/* # 所有別名 GET /_alias/* -- { "my_target_index2" : { "aliases" : { "my_search_indices" : { } } }, "my_source_index2" : { "aliases" : { "alias222" : { } } }, ".kibana_1" : { "aliases" : { ".kibana" : { } } }, "my_source_index" : { "aliases" : { "alias111" : { } } }, "my_target_index" : { "aliases" : { "my_search_indices" : { } } } }
如果要刪除
# 刪除別名 DELETE /my_source_index/_alias/alias111 -- { "acknowledged" : true }
Java
/** * 獲取別名 * @return * @throws IOException */ public static RestHighLevelClient getAlias() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetAliasesRequest request = new GetAliasesRequest(); request.aliases("alias222"); request.indices("my_source_index2"); // GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1"); // GetAliasesRequest requestWithAliases = // new GetAliasesRequest(new String[]{"alias1", "alias2"}); GetAliasesResponse response = client.indices().getAlias(request, RequestOptions.DEFAULT); Map<String, Set<AliasMetaData>> aliases = response.getAliases(); aliases.keySet().forEach(e -> { Set<AliasMetaData> aliasMetaData = aliases.get(e); System.out.println(e + ":" + aliasMetaData.toString()); }); return client; }
結果:
my_source_index2:[{ "alias222" : { } }]
14.19 Update Indices Settings
HTTP
# 更新setting PUT /twitter/_settings { "index" : { "number_of_replicas" : 2, "refresh_interval" : "1s" } }
Java
/** * 更新setting * @return * @throws IOException */ public static RestHighLevelClient updateSetting() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); // 更新單個 UpdateSettingsRequest request = new UpdateSettingsRequest("index1"); // 更新多個 //UpdateSettingsRequest requestMultiple = // new UpdateSettingsRequest("index1", "index2"); // 全部更新 //UpdateSettingsRequest requestAll = new UpdateSettingsRequest(); Settings settings = Settings.builder() .put("index.number_of_replicas", 2) .build(); request.settings(settings); AcknowledgedResponse updateSettingsResponse = client.indices().putSettings(request, RequestOptions.DEFAULT); boolean acknowledged = updateSettingsResponse.isAcknowledged(); System.out.println(acknowledged); return client; }
14.20 Get Settings
HTTP
# 獲取指定索引的settings GET /twitter,kimchy/_settings # 獲取全部settings GET /_all/_settings
Java
/** * 獲取setting * @return * @throws IOException */ public static RestHighLevelClient getSetting() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetSettingsRequest request = new GetSettingsRequest().indices("china_index"); GetSettingsResponse getSettingsResponse = client.indices().getSettings(request, RequestOptions.DEFAULT); ImmutableOpenMap<String, Settings> settings = getSettingsResponse.getIndexToSettings(); settings.forEach(e -> { System.out.println(e.key); Settings value = e.value; value.keySet().forEach(k -> { System.out.println(k + ":" + value.get(k)); }); }); return client; }
結果:
china_index index.creation_date:1545294776325 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:china_index index.uuid:LYn6XQ_sRZCazMtweW31ZA index.version.created:6050099
14.21 Put Template & Get Templates
# 索引模板 PUT _template/template_1 { "index_patterns": ["te*", "bar*"], "settings": { "number_of_shards": 1 }, "mappings": { "my_doc": { "_source": { "enabled": false }, "properties": { "host_name": { "type": "keyword" }, "created_at": { "type": "date", "format": "EEE MMM dd HH:mm:ss Z YYYY" } } } } } # 刪除模板 DELETE /_template/template_1 # 獲取模板 GET /_template/template_1 # 獲取所有模板 GET /_template # 模板是否存在 HEAD _template/template_1
14.22 Validate Query
public static RestHighLevelClient validateQuery() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); // ValidateQueryRequest需要一個或多個索引來驗證查詢。如果沒有提供索引,則在所有索引上執行請求。 ValidateQueryRequest request = new ValidateQueryRequest("twitter"); QueryBuilder builder = QueryBuilders .boolQuery() .must(QueryBuilders.queryStringQuery("*:*")) .filter(QueryBuilders.termQuery("user", "kimchy")); request.query(builder); request.allShards(true);// 默認情況下,請求只在一個隨機選擇的分片上執行 request.explain(true); request.rewrite(true); ValidateQueryResponse response = client.indices().validateQuery(request, RequestOptions.DEFAULT); boolean isValid = response.isValid(); int totalShards = response.getTotalShards(); int successfulShards = response.getSuccessfulShards(); int failedShards = response.getFailedShards(); System.out.println("isValid:" + isValid + ",totalShards:" + totalShards + ",successfulShards:" + successfulShards + ",failedShards:" + failedShards); if (failedShards > 0) { for(DefaultShardOperationFailedException failure: response.getShardFailures()) { String failedIndex = failure.index(); int shardId = failure.shardId(); String reason = failure.reason(); System.out.println("failedIndex:" + failedIndex + ",shardId:" + shardId + ",reason:" + reason); } } for(QueryExplanation explanation: response.getQueryExplanation()) { String explanationIndex = explanation.getIndex(); int shardId = explanation.getShard(); String explanationString = explanation.getExplanation(); System.out.println("explanationIndex:" + explanationIndex + ",shardId:" + shardId + ",explanationString:" + explanationString); } return client; }
結果:
isValid:true,totalShards:5,successfulShards:5,failedShards:0 explanationIndex:twitter,shardId:0,explanationString:ConstantScore(user:kimchy) explanationIndex:twitter,shardId:1,explanationString:ConstantScore(user:kimchy) explanationIndex:twitter,shardId:2,explanationString:ConstantScore(user:kimchy) explanationIndex:twitter,shardId:3,explanationString:ConstantScore(user:kimchy) explanationIndex:twitter,shardId:4,explanationString:ConstantScore(user:kimchy)
14.23 Get Index
HTTP
# 獲取所有索引信息 GET /_all # 單個索引信息 GET /twitter
Java
/** * 獲取索引詳細信息 * @return * @throws IOException */ public static RestHighLevelClient getIndex() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); GetIndexRequest request = new GetIndexRequest().indices("_all"); // _all是關鍵字,列出所有索引信息。也可以是通配符* GetIndexResponse indexResponse = client.indices().get(request, RequestOptions.DEFAULT); // Mappings ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings = indexResponse.getMappings(); mappings.forEach(e -> { String key = e.key; ImmutableOpenMap<String, MappingMetaData> map = e.value; System.out.println("Index:" + key); map.forEach(n -> { String type = n.key; MappingMetaData metaData = n.value; System.out.println(type + "|" + metaData.getSourceAsMap()); }); }); // Aliases System.out.println("**********************************"); ImmutableOpenMap<String, List<AliasMetaData>> aliases = indexResponse.getAliases(); aliases.forEach(e -> { String key = e.key; List<AliasMetaData> value = e.value; System.out.println("----" + key + "----"); value.forEach(a -> { System.out.println(a.alias()); }); }); // Settings System.out.println("**********************************"); ImmutableOpenMap<String, Settings> defaultSettings = indexResponse.defaultSettings(); defaultSettings.forEach(e -> { String key = e.key; Settings value = e.value; System.out.println("----" + key + "----"); value.keySet().forEach(k -> { System.out.println(k + ":" + value.get(k)); }); }); ImmutableOpenMap<String, Settings> settings = indexResponse.getSettings(); settings.forEach(e -> { String key = e.key; Settings value = e.value; System.out.println("----" + key + "----"); value.keySet().forEach(k -> { System.out.println(k + ":" + value.get(k)); }); }); return client; }
結果:
Index:china_shape_index info|{properties={location={precision=100.0m, type=geo_shape}, remark={type=keyword}}} Index:china_index city|{properties={pName={type=keyword}, cName={type=text}, location={type=geo_point}}} Index:books java|{properties={title={type=text, fields={keyword={ignore_above=256, type=keyword}}}, user={type=text, fields={keyword={ignore_above=256, type=keyword}}}}} Index:my_source_index2 Index:my_target_index2 Index:my_source_index Index:users info|{properties={address={analyzer=ik_max_word, type=text}, age={type=long}, username={type=keyword}}} Index:my_target_index Index:test msg|{properties={message={analyzer=ik_max_word, type=text}}} Index:.kibana_1 doc|{dynamic=strict, properties={server={properties={uuid={type=keyword}}}, visualization={properties={savedSearchId={type=keyword}, description={type=text}, uiStateJSON={type=text}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, visState={type=text}}}, graph-workspace={properties={numVertices={type=integer}, description={type=text}, numLinks={type=integer}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, wsState={type=text}}}, kql-telemetry={properties={optInCount={type=long}, optOutCount={type=long}}}, type={type=keyword}, space={properties={color={type=keyword}, _reserved={type=boolean}, initials={type=keyword}, name={type=text, fields={keyword={ignore_above=2048, type=keyword}}}, description={type=text}}}, url={properties={accessCount={type=long}, accessDate={type=date}, url={type=text, fields={keyword={ignore_above=2048, type=keyword}}}, createDate={type=date}}}, migrationVersion={dynamic=true, type=object}, index-pattern={properties={notExpandable={type=boolean}, fieldFormatMap={type=text}, sourceFilters={type=text}, typeMeta={type=keyword}, timeFieldName={type=keyword}, intervalName={type=keyword}, fields={type=text}, title={type=text}, type={type=keyword}}}, search={properties={hits={type=integer}, columns={type=keyword}, description={type=text}, sort={type=keyword}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}}}, updated_at={type=date}, canvas-workpad={dynamic=false, properties={@created={type=date}, @timestamp={type=date}, name={type=text, fields={keyword={type=keyword}}}, id={index=false, type=text}}}, namespace={type=keyword}, telemetry={properties={enabled={type=boolean}}}, timelion-sheet={properties={hits={type=integer}, timelion_sheet={type=text}, timelion_interval={type=keyword}, timelion_columns={type=integer}, timelion_other_interval={type=keyword}, timelion_rows={type=integer}, description={type=text}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, timelion_chart_height={type=integer}}}, config={dynamic=true, properties={buildNum={type=keyword}}}, dashboard={properties={hits={type=integer}, timeFrom={type=keyword}, timeTo={type=keyword}, refreshInterval={properties={display={type=keyword}, section={type=integer}, value={type=integer}, pause={type=boolean}}}, description={type=text}, uiStateJSON={type=text}, timeRestore={type=boolean}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, optionsJSON={type=text}, panelsJSON={type=text}}}}} Index:twitter t_doc|{properties={msg={type=text, fields={keyword={ignore_above=256, type=keyword}}}, A={type=text, fields={keyword={ignore_above=256, type=keyword}}}, B={type=text, fields={keyword={ignore_above=256, type=keyword}}}, C={type=text, fields={keyword={ignore_above=256, type=keyword}}}, flag={type=text, fields={keyword={ignore_above=256, type=keyword}}}, D={type=text, fields={keyword={ignore_above=256, type=keyword}}}, color={type=text, fields={keyword={ignore_above=256, type=keyword}}}, updateUser={type=text, fields={keyword={ignore_above=256, type=keyword}}}, extMsg={type=text, fields={keyword={ignore_above=256, type=keyword}}}, counter={type=long}, message={type=text, fields={keyword={ignore_above=256, type=keyword}}}, field={type=text, fields={keyword={ignore_above=256, type=keyword}}}, size={type=text, fields={keyword={ignore_above=256, type=keyword}}}, post_date={type=date}, name={type=text, fields={keyword={ignore_above=256, type=keyword}}}, animal={properties={cat={type=text, fields={keyword={ignore_above=256, type=keyword}}}, dog={type=text, fields={keyword={ignore_above=256, type=keyword}}}}}, postDate={type=date}, hate={type=text, fields={keyword={ignore_above=256, type=keyword}}}, favorite={type=text, fields={keyword={ignore_above=256, type=keyword}}}, user={type=text, fields={keyword={ignore_above=256, type=keyword}}}}} ********************************** ----china_shape_index---- ----.kibana_1---- .kibana ----china_index---- ----users---- ----my_source_index---- ----my_source_index2---- alias222 ----my_target_index2---- my_search_indices ----my_target_index---- my_search_indices ----test---- ----twitter---- ----books---- ********************************** ----my_target_index---- index.allocation.max_retries:1 index.blocks.write:true index.codec:best_compression index.creation_date:1546589354014 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:my_target_index index.resize.source.name:my_source_index index.resize.source.uuid:tSYNLldWQNCOlR5NJGaH9g index.routing.allocation.initial_recovery._id:wCr6Uz0jTvGaTHh5acNxKA index.routing_partition_size:1 index.shrink.source.name:my_source_index index.shrink.source.uuid:tSYNLldWQNCOlR5NJGaH9g index.uuid:F976xviGQ965JU9patwQnA index.version.created:6050099 index.version.upgraded:6050099 ----twitter---- index.creation_date:1545622508123 index.number_of_replicas:1 index.number_of_shards:5 index.provided_name:twitter index.uuid:TLReCXTSSe6tvI7yNveWgw index.version.created:6050099 ----books---- index.creation_date:1545708244767 index.number_of_replicas:1 index.number_of_shards:5 index.provided_name:books index.uuid:leQWEGe8So6B10awTItCNg index.version.created:6050099 ----users---- index.creation_date:1545967628013 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:users index.uuid:tyxNGtSsThOFDaTBBy7jKQ index.version.created:6050099 ----my_source_index---- index.blocks.write:true index.creation_date:1546589291669 index.number_of_replicas:2 index.number_of_shards:4 index.provided_name:my_source_index index.uuid:tSYNLldWQNCOlR5NJGaH9g index.version.created:6050099 ----my_source_index2---- index.blocks.write:true index.creation_date:1546590226265 index.number_of_replicas:1 index.number_of_shards:2 index.provided_name:my_source_index2 index.uuid:iuDENl3uQku0Ef6flu8S-Q index.version.created:6050099 ----test---- index.creation_date:1545791918478 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:test index.uuid:qF3UiIqHTLK_X7FSUUhlGw index.version.created:6050099 ----china_shape_index---- index.creation_date:1545981755548 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:china_shape_index index.uuid:jhwyVqR0RQywyf3n7W0maQ index.version.created:6050099 ----china_index---- index.creation_date:1545294776325 index.number_of_replicas:1 index.number_of_shards:1 index.provided_name:china_index index.uuid:LYn6XQ_sRZCazMtweW31ZA index.version.created:6050099 ----.kibana_1---- index.auto_expand_replicas:0-1 index.creation_date:1542353618696 index.number_of_replicas:0 index.number_of_shards:1 index.provided_name:.kibana_1 index.uuid:IvzG6JhgRJ-GgwTDWmmirQ index.version.created:6050099 ----my_target_index2---- index.blocks.write:true index.creation_date:1546590255143 index.number_of_replicas:1 index.number_of_shards:4 index.provided_name:my_target_index2 index.resize.source.name:my_source_index2 index.resize.source.uuid:iuDENl3uQku0Ef6flu8S-Q index.routing_partition_size:1 index.uuid:ZBnocs2bSker45kb2lXoRw index.version.created:6050099 index.version.upgraded:6050099 Process finished with exit code 0
完