说明
TransportClient:网上流传最多的客户端,目前最新版本
Java REST Client:官方推荐的客户端,
官方:我们要在Elasticsearch 7.0的版本中不赞成使用TransportClient,在Elasticsearch 8.0的版本中完全移除TransportClient。转而使用Java REST Client
照这个势头看,现在都6.5了,8.0还会远嘛。使用客户端要注意版本对应的问题,最好版本完全一致,实在不行也要保障主版本一致,比如5.X 、 6.X
TransportClient
连接
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import java.net.InetAddress; import java.net.UnknownHostException; public class TransportClientFactory { private TransportClientFactory(){} private static class Inner{ private static final TransportClientFactory instance = new TransportClientFactory(); } public static TransportClientFactory getInstance(){ return Inner.instance; } public TransportClient getClient() throws UnknownHostException { Settings settings = Settings.builder() .put("cluster.name", "my-elasticsearch") // 默认的集群名称是elasticsearch,如果不是要指定 .build(); return new PreBuiltTransportClient(settings) //.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9301)) .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300)); } }
Index
1. 添加文档
public static TransportClient addDoc1() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); // 构建对象 XContentBuilder builder = jsonBuilder() .startObject() .field("brand", "ANTA") .field("color", "red") .field("model", "S") .field("postDate", new Date()) .endObject(); // 转成JSON格式 String json = Strings.toString(builder); /** * 参数1:index * 参数2:type * 参数3:id */ IndexRequestBuilder indexRequestBuilder = client.prepareIndex("clothes", "young", "1"); IndexResponse response = indexRequestBuilder.setSource(json, XContentType.JSON).get(); System.out.println("Index:" + response.getIndex() + "," + "Type:" + response.getType() + "," + "ID:" + response.getId() + "," + "Version:" + response.getVersion() + "," + "Status:" + response.status().name() ); return client; }
执行结果:
Index:clothes,Type:young,ID:1,Version:1,Status:CREATED
2. 添加文档还可以不指定id,这个时候默认生成一个唯一id
public static TransportClient addDoc2() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); // 构建对象 XContentBuilder builder = jsonBuilder() .startObject() .field("brand", "YISHION") .field("color", "Blue") .field("model", "S") .field("postDate", new Date()) .endObject(); // 转成JSON格式 String json = Strings.toString(builder); /** * 参数1:index * 参数2:type */ IndexRequestBuilder indexRequestBuilder = client.prepareIndex("clothes", "young"); IndexResponse response = indexRequestBuilder.setSource(json, XContentType.JSON).get(); System.out.println("Index:" + response.getIndex() + "," + "Type:" + response.getType() + "," + "ID:" + response.getId() + "," + "Version:" + response.getVersion() + "," + "Status:" + response.status().name() ); return client; }
执行结果:
Index:clothes,Type:young,ID:J5uAoWcBb9TcvgEh2GJ3,Version:1,Status:CREATED
3. 根据id获取文档
/** * 根据id获取 * @throws IOException */ public static TransportClient getDoc() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); // prepareGet 参数分别为index、type、id GetResponse response = client.prepareGet("clothes", "young", "1").get(); String id = response.getId(); String index = response.getIndex(); Map<String, DocumentField> fields = response.getFields(); // 返回的source,也就是数据源 Map<String, Object> source = response.getSource(); System.out.println("ID:" + id + ",Index:" + index); Set<String> fieldKeys = fields.keySet(); for (String s : fieldKeys){ DocumentField documentField = fields.get(s); String name = documentField.getName(); List<Object> values = documentField.getValues(); System.out.println(name + ":" + values.toString()); } System.out.println("=========="); Set<String> sourceKeys = source.keySet(); for(String s : sourceKeys){ Object o = source.get(s); System.out.println(s + ":" + o); } return client; }
执行结果:
ID:1,Index:clothes ========== color:red postDate:2018-12-12T08:18:21.509Z model:S brand:ANTA
4. 根据id删除,我们删除那个默认生成的那个id
/** * 根据id删除 * @throws IOException */ public static TransportClient delDoc() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); DeleteResponse response = client.prepareDelete("clothes", "young", "J5uAoWcBb9TcvgEh2GJ3").get(); String id = response.getId(); String index = response.getIndex(); String status = response.status().name(); System.out.println("ID:" + id + ",Index:" + index + ",Status:" + status); return client; }
执行结果:
ID:J5uAoWcBb9TcvgEh2GJ3,Index:clothes,Status:OK
5. 根据条件删除
/** * 根据条件删除 * @throws IOException */ public static TransportClient delDocByQuery() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); BulkByScrollResponse response = DeleteByQueryAction.INSTANCE.newRequestBuilder(client) .filter(QueryBuilders.matchQuery("brand", "ANTA")) // 属性-值 .source("clothes") // index .get(); long deleted = response.getDeleted(); System.out.println(deleted); return client; }
执行结果:
1
这里第一次遇到QueryBuilders,这个东西很常用,回头我介绍这个类。
根据条件删除还可以指定type
DeleteByQueryRequestBuilder builder = DeleteByQueryAction.INSTANCE.newRequestBuilder(client); builder.filter(QueryBuilders.matchQuery("brand", "ANTA")) // 属性-值 .source("clothes") // index .source().setTypes("young"); // type BulkByScrollResponse response = builder.get();
6. 批量插入(这个bulk不仅可以批量创建,也可以更新或者删除)
/** * 批量插入 * @throws IOException */ public static TransportClient bulkDoc() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); BulkRequestBuilder bulk = client.prepareBulk(); bulk.add(client.prepareIndex("car", "model", "1") .setSource(jsonBuilder() .startObject() .field("name", "法拉利488") .field("price", "315.50-418.80万") .field("postDate", new Date()) .endObject() ) ); bulk.add(client.prepareIndex("car", "model", "2") .setSource(jsonBuilder() .startObject() .field("name", "法拉利LaFerrari") .field("price", "2250.00万") .field("postDate", new Date()) .endObject() ) ); bulk.add(client.prepareIndex("car", "model", "3") .setSource(jsonBuilder() .startObject() .field("name", "法拉利GTC4Lusso") .field("price", "322.80-485.80万") .field("postDate", new Date()) .endObject() ) ); BulkResponse responses = bulk.get(); String status = responses.status().name(); System.out.println(status); return client; }
执行结果:
OK
7. 获取多个结果
/** * 批量获取 * @throws IOException */ public static TransportClient multiGetDoc() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); MultiGetResponse multiGetItemResponses = client.prepareMultiGet() // 可以指定多个index,多个id .add("clothes", "young", "1", "2") .add("car", "model", "1","2","3") .get(); for (MultiGetItemResponse itemResponse : multiGetItemResponses) { GetResponse response = itemResponse.getResponse(); if (response.isExists()) { String json = response.getSourceAsString(); System.out.println(json); } } return client; }
执行结果:由于之前clothes里面没数据了,所以只显示了下面三条数据
{"name":"法拉利488","price":"315.50-418.80万","postDate":"2018-12-12T08:38:09.107Z"} {"name":"法拉利LaFerrari","price":"2250.00万","postDate":"2018-12-12T08:38:09.129Z"} {"name":"法拉利GTC4Lusso","price":"322.80-485.80万","postDate":"2018-12-12T08:38:09.129Z"}
8. 更新
/** * 更新方式一:通过UpdateRequest * @throws IOException * @throws ExecutionException * @throws InterruptedException */ public static TransportClient updateDoc1() throws IOException, ExecutionException, InterruptedException { TransportClient client = TransportClientFactory.getInstance().getClient(); UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index("car"); // 指定index updateRequest.type("model");// 指定type updateRequest.id("3"); // 指定id // 更新内容 updateRequest.doc(jsonBuilder() .startObject() .field("name", "Aventador") .field("price", "630.00-755.94万") .field("postDate", new Date()) .field("extra", "Extra Data") // 不存在的会自动添加 .endObject()); UpdateResponse updateResponse = client.update(updateRequest).get(); System.out.println(updateResponse.status().name()); return client; }
执行结果:
OK
在Kibana上查看结果:GET /car/model/3
客户端有两种请求方式,一种是***Request(比如UpdateRequest ),另一种是prepare***(比如prepareUpdate),我更喜欢用prepare***
/** * 更新方式二:通过prepareUpdate * @throws IOException */ public static TransportClient updateDoc2() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); client.prepareUpdate("car", "model", "1") .setDoc(jsonBuilder() .startObject() .field("name", "法拉利812 Superfast") .field("price", "498.80万") .field("postDate", new Date()) .endObject() ) .get(); return client; }
9. upset更新
/** * 文档存在则更新doc,不存在则添加upsert * @throws IOException * @throws ExecutionException * @throws InterruptedException */ public static TransportClient upsert() throws IOException, ExecutionException, InterruptedException { TransportClient client = TransportClientFactory.getInstance().getClient(); IndexRequest indexRequest = new IndexRequest("clothes", "young", "3") .source(jsonBuilder() .startObject() .field("brand", "Pierre Cardin") .field("color", "Black") .field("model", "L") .field("postDate", new Date()) .endObject()); UpdateRequest updateRequest = new UpdateRequest("clothes", "young", "3") .doc(jsonBuilder() .startObject() .field("model", "XL") .endObject()) .upsert(indexRequest); UpdateResponse response = client.update(updateRequest).get(); System.out.println(response.status().name()); return client; }
什么意思呢,如果文档存在,则只更新model字段,相反会添加IndexRequest里面的内容。
第一次执行:(文档不存在)
CREATED
GET /clothes/young/3
第二次执行:
OK
查看Kibana
10. bulkProcessor 另外一个批量工具
基本的配置
.setBulkActions(10000) // 每10000个request,bulk一次 .setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB)) // 每5M的数据刷新一次 .setFlushInterval(TimeValue.timeValueSeconds(5)) // 每5s刷新一次,而不管有多少数据量 .setConcurrentRequests(0) // 设置并发请求的数量。值为0意味着只允许执行一个请求。值为1意味着在积累新的批量请求时允许执行1个并发请求。 .setBackoffPolicy( // 设置一个自定义的重试策略,该策略最初将等待100毫秒,按指数增长,最多重试3次。当一个或多个批量项请求失败时,如果出现EsRejectedExecutionException异常,将尝试重试,该异常表明用于处理请求的计算资源太少。要禁用backoff,请传递BackoffPolicy.noBackoff()。 BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
测试
/** * 造数据 * @throws IOException */ public static TransportClient scrollSearchPreData() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); BulkProcessor bulkProcessor = BulkProcessor.builder( client, new BulkProcessor.Listener() { @Override public void beforeBulk(long executionId, BulkRequest request) { // bulk 执行之前 System.out.println("beforeBulk-----" + request.getDescription()); } @Override public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { // bulk 执行之后 System.out.println("afterBulk------" + request.getDescription() + ",是否有错误:" + response.hasFailures()); } @Override public void afterBulk(long executionId, BulkRequest request, Throwable failure) { //bulk 失败 System.out.println("报错-----" + request.getDescription() + "," + failure.getMessage()); } }) .setBulkActions(100) // 每100个request,bulk一次 .setConcurrentRequests(0) // 设置并发请求的数量。值为0意味着只允许执行一个请求。值为1意味着在积累新的批量请求时允许执行1个并发请求。 .build(); Random random = new Random(); for (int i = 1; i <= 1000; i++){ bulkProcessor.add(new IndexRequest("book", "elasticsearch", i+"").source(jsonBuilder() .startObject() .field("name", "book_" + i) .field("price", random.nextDouble()*1000) .field("postDate", new Date()) .endObject())); } bulkProcessor.flush(); bulkProcessor.close(); return client; }
执行结果:1000条数据,bulk10次
beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false beforeBulk-----requests[100], indices[book] afterBulk------requests[100], indices[book],是否有错误:false
11. scroll(让数据都滚出来)
/** * 当搜索请求返回一个结果的“页面”时,滚动API可以用于从一个搜索请求检索大量的结果(甚至所有结果) * 其方式与在传统数据库中使用游标非常类似。滚动不是为了实时的用户请求,而是为了处理大量的数据 * @throws UnknownHostException */ public static TransportClient scrollSearch() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse response = client.prepareSearch("book") .addSort("price", SortOrder.ASC) .setScroll(new TimeValue(30000)) .setSize(1000).get(); // 每次滚出1000条就返回 do { System.out.println("========Begin======="); for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsString()); } System.out.println("========End======="); response = client.prepareSearchScroll(response.getScrollId()).setScroll(new TimeValue(30000)).execute().actionGet(); } while(response.getHits().getHits().length != 0); return client; }
执行结果:
========Begin======= {"name":"book_233","price":0.7903630819869889,"postDate":"2018-12-12T09:27:32.629Z"} {"name":"book_46","price":1.9862330698061648,"postDate":"2018-12-12T09:27:30.722Z"} {"name":"book_18","price":2.8024592316934216,"postDate":"2018-12-12T09:27:30.721Z"} {"name":"book_512","price":3.5739663933835875,"postDate":"2018-12-12T09:27:33.275Z"} {"name":"book_275","price":5.449351054677254,"postDate":"2018-12-12T09:27:32.632Z"} {"name":"book_112","price":8.035476335226166,"postDate":"2018-12-12T09:27:32.424Z"} ...此处省略 ========End=======
12. 根据查询更新
/** * 当版本匹配时,updateByQuery更新文档并增加版本号。 * 所有更新和查询失败都会导致updateByQuery中止。这些故障可从BulkByScrollResponse#getBulkFailures方法中获得。 * 任何成功的更新都会保留并不会回滚。当第一个失败导致中止时,响应包含由失败的批量请求生成的所有失败。 * 当文档在快照时间和索引请求过程时间之间发生更改时,就会发生版本冲突 * 为了防止版本冲突导致updateByQuery中止,设置abortOnVersionConflict(false)。 * ScriptType.INLINE:在大量查询中指定内联脚本并动态编译。它们将基于脚本的lang和代码进行缓存。 * ScriptType.STORED:存储的脚本作为{@link org.elasticsearch.cluster.ClusterState}的一部分保存基于用户请求。它们将在查询中首次使用时被缓存。 * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-update-by-query.html * https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html * @throws UnknownHostException */ public static TransportClient updateByQuery() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client); updateByQuery.source("book") .size(100) // 尝试获取的最大文档数 .filter(QueryBuilders.termsQuery("name","book_233", "book_46", "book_18", "book_512")) // 注意term,value要变成小写!! // 以下脚本:保留id=781的,删除id=316的,其它的价格都变为79 .script(new Script( ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG, "if (ctx._source['id'] == 781) {" + " ctx.op='noop'" // ctx.op='noop' 不做处理 + "} else if (ctx._source['id'] == '316') {" + " ctx.op='delete'" // ctx.op='delete'删除 + "} else {" + "ctx._source['price'] = 79}", Collections.emptyMap())) .abortOnVersionConflict(false); // 版本冲突策略:abortOnVersionConflict 版本冲突时不终止 // .source().setTypes("young") // 指定type // .setSize(10) // 返回搜索的命中数 // .addSort("postDate", SortOrder.DESC); BulkByScrollResponse response = updateByQuery.get(); System.out.println("Deleted:" + response.getDeleted() + ",Created:" + response.getCreated() + ",Updated:" + response.getUpdated() + ",Noops:" + response.getNoops()); List<BulkItemResponse.Failure> failures = response.getBulkFailures(); System.out.println(failures.size()); // 如果目标值是Cat,更新内容也是Cat,则不会去更新 return client; }
执行结果:(这个term查询有点坑,value必须为小写,并且不能带-,我之前生成的格式为book-100,结果查询不出来。。。)
Deleted:0,Created:0,Updated:4,Noops:0 0
查看数据:
GET /book/elasticsearch/_mget { "ids" : ["233", "46", "18", "512"] }
结果:
{ "docs" : [ { "_index" : "book", "_type" : "elasticsearch", "_id" : "233", "_version" : 2, "found" : true, "_source" : { "price" : 79, "name" : "book_233", "postDate" : "2018-12-12T09:27:32.629Z" } }, { "_index" : "book", "_type" : "elasticsearch", "_id" : "46", "_version" : 2, "found" : true, "_source" : { "price" : 79, "name" : "book_46", "postDate" : "2018-12-12T09:27:30.722Z" } }, { "_index" : "book", "_type" : "elasticsearch", "_id" : "18", "_version" : 2, "found" : true, "_source" : { "price" : 79, "name" : "book_18", "postDate" : "2018-12-12T09:27:30.721Z" } }, { "_index" : "book", "_type" : "elasticsearch", "_id" : "512", "_version" : 2, "found" : true, "_source" : { "price" : 79, "name" : "book_512", "postDate" : "2018-12-12T09:27:33.275Z" } } ] }
13. 简单查询
/** * 简单查询【通配符查询,筛选价格范围,设定返回数量,排序】 * @throws UnknownHostException */ public static TransportClient search() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse response = client.prepareSearch("book") // index,可以多个 .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.wildcardQuery("name", "*book_1*")) // Query .setPostFilter(QueryBuilders.rangeQuery("price").from(800).to(900)) // Filter .setFrom(0).setSize(100).setExplain(true).addSort("postDate", SortOrder.DESC) .get(); response.getHits().forEach(e ->{ System.out.println(e.getSourceAsString()); }); return client; }
执行结果:
{"name":"book_1000","price":811.3812414198577,"postDate":"2018-12-12T09:27:34.095Z"} {"name":"book_194","price":828.6484294585816,"postDate":"2018-12-12T09:27:32.433Z"} {"name":"book_171","price":839.1475764183831,"postDate":"2018-12-12T09:27:32.432Z"} {"name":"book_170","price":869.7835076374234,"postDate":"2018-12-12T09:27:32.431Z"} {"name":"book_161","price":838.5131747806441,"postDate":"2018-12-12T09:27:32.429Z"} {"name":"book_153","price":805.041724108352,"postDate":"2018-12-12T09:27:32.429Z"} {"name":"book_154","price":893.982844708382,"postDate":"2018-12-12T09:27:32.429Z"} {"name":"book_105","price":883.039302643907,"postDate":"2018-12-12T09:27:32.424Z"} {"name":"book_19","price":877.0523728410054,"postDate":"2018-12-12T09:27:30.721Z"}
14. 多个查询MultiSearch
/** * 多个查询 */ public static TransportClient multiSearch() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); // 第一个查询 SearchRequestBuilder srb1 = client .prepareSearch("book") .setQuery(QueryBuilders.queryStringQuery("book_9*").field("name")) .setFrom(0) // 开始位置 .setSize(10); // 设置返回的最大条数 // 第二个查询 SearchRequestBuilder srb2 = client .prepareSearch("car") .setQuery(QueryBuilders.queryStringQuery("*r*")) .setSize(10); // 组合 MultiSearchResponse sr = client.prepareMultiSearch() .add(srb1) .add(srb2) .get(); // You will get all individual responses from MultiSearchResponse#getResponses() long nbHits = 0; for (MultiSearchResponse.Item item : sr.getResponses()) { SearchResponse response = item.getResponse(); response.getHits().forEach(e ->{ System.out.println(e.getSourceAsString()); }); long hits = response.getHits().getTotalHits(); System.out.println("Hits:" + hits); nbHits += hits; } System.out.println("Total:" + nbHits); return client; }
执行结果:
{"name":"book_92","price":176.35847694096162,"postDate":"2018-12-12T09:27:30.724Z"} {"name":"book_98","price":611.4318589503413,"postDate":"2018-12-12T09:27:30.724Z"} {"name":"book_99","price":214.4653626273969,"postDate":"2018-12-12T09:27:30.724Z"} {"name":"book_900","price":973.3382073380857,"postDate":"2018-12-12T09:27:33.892Z"} {"name":"book_915","price":35.30856326485343,"postDate":"2018-12-12T09:27:34.091Z"} {"name":"book_922","price":299.58144612743064,"postDate":"2018-12-12T09:27:34.091Z"} {"name":"book_930","price":591.6598815227311,"postDate":"2018-12-12T09:27:34.092Z"} {"name":"book_933","price":287.18727780940037,"postDate":"2018-12-12T09:27:34.092Z"} {"name":"book_935","price":693.6036227965725,"postDate":"2018-12-12T09:27:34.092Z"} {"name":"book_942","price":701.4129722487066,"postDate":"2018-12-12T09:27:34.092Z"} Hits:111 {"name":"法拉利LaFerrari","price":"2250.00万","postDate":"2018-12-12T08:38:09.129Z"} {"name":"Aventador","price":"630.00-755.94万","postDate":"2018-12-12T08:49:01.736Z","extra":"Extra Data"} Hits:2 Total:113
聚合
15. 聚合查询
/** * 聚合查询 * 搜索是查找某些具体的文档.然而聚合就是对这些搜索到的文档进行统计 * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-aggs.html * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search-aggs.html * 可以在聚合中定义子聚合 * @return * @throws UnknownHostException */ public static TransportClient aggregationsSearch() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse sr = client.prepareSearch("book") .setQuery(QueryBuilders.matchAllQuery()) .addAggregation( AggregationBuilders.stats("agg1").field("price") ) .addAggregation( AggregationBuilders.dateHistogram("agg2") .field("postDate") .dateHistogramInterval(DateHistogramInterval.YEAR) ) .get(); // Short version of execute().actionGet(). // Get your facet results Aggregation agg1 = sr.getAggregations().get("agg1"); System.out.println(agg1.getClass()); // class org.elasticsearch.search.aggregations.metrics.stats.InternalStats Aggregation agg2 = sr.getAggregations().get("agg2"); System.out.println(agg2.getClass()); // class org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram return client; }
15.1 metrics聚合
/** * metrics聚合 * 主要为了统计信息 * org.elasticsearch.search.aggregations.metrics.percentiles.Percentiles * org.elasticsearch.search.aggregations.metrics.percentiles.PercentileRanks * org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality * 地理位置聚合:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_metrics_aggregations.html#java-aggs-metrics-geobounds * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_metrics_aggregations.html#java-aggs-metrics-tophits * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_metrics_aggregations.html#java-aggs-metrics-scripted-metric * @return * @throws UnknownHostException */ public static TransportClient metricsAggregationsSearch() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse sr = client.prepareSearch("book") .setQuery(QueryBuilders.matchAllQuery()) .addAggregation( AggregationBuilders.min("agg1").field("price") ) .addAggregation( AggregationBuilders.max("agg2").field("price") ) .addAggregation( AggregationBuilders.sum("agg3").field("price") ) .addAggregation( AggregationBuilders.avg("agg4").field("price") ) .addAggregation( AggregationBuilders.count("agg5").field("price") ) .addAggregation( AggregationBuilders.stats("agg6").field("price") ) .get(); Min agg1 = sr.getAggregations().get("agg1"); Max agg2 = sr.getAggregations().get("agg2"); Sum agg3 = sr.getAggregations().get("agg3"); Avg agg4 = sr.getAggregations().get("agg4"); ValueCount agg5 = sr.getAggregations().get("agg5"); Stats agg6 = sr.getAggregations().get("agg6"); System.out.println("Min:" + agg1.getValue() + ",Max:" + agg2.getValue() + ",Sum:" + agg3.getValue() + ",Avg:" + agg4.getValue() + ",Count:" + agg5.getValue() + ",Stats:(" + agg6.getMin() + "," + agg6.getMax() + "," + agg6.getSum() + "," + agg6.getAvg() + "," + agg6.getCount() + ")"); return client; }
执行结果:
Min:5.449350833892822,Max:999.3211669921875,Sum:502966.58267736435,Avg:502.96658267736433,Count:1000,Stats:(5.449350833892822,999.3211669921875,502966.58267736435,502.96658267736433,1000)
15.2地理位置聚合(计算坐标的左上/右下边界值)
/** * 准备地理位置信息 * @return * @throws IOException */ public static TransportClient geoSearchPreData() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); // 建立索引 CreateIndexResponse indexResponse = client.admin().indices().prepareCreate("area") .setSettings(Settings.builder() .put("index.number_of_shards", 1) // 分片 .put("index.number_of_replicas", 1) // 副本 ) .addMapping("hospital", "message", "type=text", "location", "type=geo_point") .get(); System.out.println("Index:" + indexResponse.index() + ",ACK:" + indexResponse.isAcknowledged()); BulkProcessor bulkProcessor = BulkProcessor.builder( client, new BulkProcessor.Listener() { @Override public void beforeBulk(long executionId, BulkRequest request) { // bulk 执行之前 System.out.println("beforeBulk-----" + request.getDescription()); } @Override public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { // bulk 执行之后 System.out.println("afterBulk------" + request.getDescription() + ",hasFailures:" + response.hasFailures()); } @Override public void afterBulk(long executionId, BulkRequest request, Throwable failure) { //bulk 失败 System.out.println("报错-----" + request.getDescription() + "," + failure.getMessage()); } }) .setBulkActions(100) // 每100个request,bulk一次 .setConcurrentRequests(0) // 设置并发请求的数量。值为0意味着只允许执行一个请求。值为1意味着在积累新的批量请求时允许执行1个并发请求。 .build(); Random random = new Random(); for (int i = 1; i <= 200; i++){ String lo = new DecimalFormat("#.############").format(random.nextDouble() * 100); String la = new DecimalFormat("#.############").format(random.nextDouble() * 100); bulkProcessor.add(new IndexRequest("area", "hospital", i+"").source(jsonBuilder() .startObject() .field("name", "hospital-" + i) .field("location", lo + "," + la) .endObject())); } bulkProcessor.flush(); bulkProcessor.close(); return client; } /** * 地理信息查询 * @return * @throws UnknownHostException */ public static TransportClient geoAggregation() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse sr = client.prepareSearch("area") .setQuery(QueryBuilders.matchQuery("name", "hospital-1")) .addAggregation( AggregationBuilders.geoBounds("agg").field("location").wrapLongitude(true) ) .get(); GeoBounds agg = sr.getAggregations().get("agg"); GeoPoint left = agg.topLeft(); GeoPoint right = agg.bottomRight(); System.out.println(left + " | " + right); return client; }
执行结果:
89.9911705031991, 0.03342803567647934 | 0.049703302793204784, 99.9249867349863
15.3桶聚合
/** * 桶聚合,我这里只列举了部分 * https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_bucket_aggregations.html * @return * @throws UnknownHostException */ public static TransportClient bucketAggregationsSearch() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse sr = client.prepareSearch() .setQuery(QueryBuilders.matchAllQuery()) // .addAggregation(AggregationBuilders // .global("agg0") // .subAggregation(AggregationBuilders.terms("sub_agg").field("name")) // ) .addAggregation(AggregationBuilders .filter("agg1", QueryBuilders.termQuery("name", "book_199"))) .addAggregation(AggregationBuilders .filters("agg2", new FiltersAggregator.KeyedFilter("key1", QueryBuilders.termQuery("name", "book_1")), new FiltersAggregator.KeyedFilter("key2", QueryBuilders.termQuery("name", "book_52")) )) .get(); // Global agg0 = sr.getAggregations().get("agg0"); // System.out.println("GlobalCount:" + agg0.getDocCount()); Filter agg1 = sr.getAggregations().get("agg1"); System.out.println("FilterCount:" + agg1.getDocCount()); Filters agg2 = sr.getAggregations().get("agg2"); for (Filters.Bucket entry : agg2.getBuckets()) { String key = entry.getKeyAsString(); // bucket key long docCount = entry.getDocCount(); // Doc count System.out.println("key [" + key + "], doc_count ["+ docCount +"]"); } return client; }
执行结果:Global会屏蔽其它的Agg
FilterCount:1 key [key1], doc_count [1] key [key2], doc_count [1]
查询DSL
16. Query DSL
16.1 MatchAll,最简单的查询,它会匹配所有文档
client.prepareSearch().setQuery(QueryBuilders.matchAllQuery());
16.2 全文检索【高级全文查询通常用于在全文字段(如电子邮件正文)上运行全文查询,在执行之前有分析的过程。】
16.2.1 Match Query(全文查询的标准查询,包括模糊匹配和短语或邻近查询)
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("book") .setQuery(QueryBuilders .matchQuery("name", "book_1") .fuzziness(Fuzziness.AUTO) // 模糊查询 .zeroTermsQuery(MatchQuery.ZeroTermsQuery.ALL) // 与MatchAll等价,匹配所有文档。默认none,不匹配任何文档 ).get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:(为什么会命中250条呢?这是因为模糊查询,如果你注释掉模糊查询,就只会查到一条)
{"name":"book_1","price":541.5683324629698,"postDate":"2018-12-12T09:27:30.695Z"} {"name":"book_2","price":859.0268161692424,"postDate":"2018-12-12T09:27:30.720Z"} {"name":"book_4","price":666.0331749730802,"postDate":"2018-12-12T09:27:30.720Z"} {"name":"book_6","price":797.3826369337273,"postDate":"2018-12-12T09:27:30.720Z"} {"name":"book_15","price":764.0761667524818,"postDate":"2018-12-12T09:27:30.721Z"} {"name":"book_51","price":969.2863955131567,"postDate":"2018-12-12T09:27:30.722Z"} {"name":"book_3","price":467.29468328850055,"postDate":"2018-12-12T09:27:30.720Z"} {"name":"book_11","price":365.2274741512962,"postDate":"2018-12-12T09:27:30.720Z"} {"name":"book_17","price":498.8900836459158,"postDate":"2018-12-12T09:27:30.721Z"} {"name":"book_31","price":377.2822748558652,"postDate":"2018-12-12T09:27:30.721Z"} 命中:250
16.2.2 Multi Match Query(标准查询的多字段版本)
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() // 关键字Aventador,匹配多个字段*ame、brand。字段名称可以使用通配符 .setQuery(QueryBuilders.multiMatchQuery("Aventador", "*ame","brand")) .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"name":"Aventador","price":"630.00-755.94万","postDate":"2018-12-12T08:49:01.736Z","extra":"Extra Data"}
命中:1
16.2.3 Common Terms Query(一个更专业的查询,偏好不常见的关键字)
...待补充
16.2.4 Query String Query(解析输入并围绕操作符拆分文本,每个文本部分都是独立分析的)
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() // 关键字和字段【均可以】可以使用通配符(?匹配一个字符,*匹配0个或多个字符,AND,OR)等等 // 有一些您不希望作为操作符的必须转义处理:+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ / //.setQuery(QueryBuilders.queryStringQuery("(book_111) OR (book_999)")) // or //.setQuery(QueryBuilders.queryStringQuery("(book_111) AND (book_999)")) // AND //.setQuery(QueryBuilders.queryStringQuery("(book_111) && (book_999)")) // AND与&&等价 //.setQuery(QueryBuilders.queryStringQuery("(book_111) & (book_999)")) // &不会短路计算 //.setQuery(QueryBuilders.queryStringQuery("book_1?1").field("name")) // ? 并且指定字段 //.setQuery(QueryBuilders.queryStringQuery("name:book_1?1 OR color:B*")) // 在查询里指定字段 //.setQuery(QueryBuilders.queryStringQuery("name:book_1?1 | color:B*")) //.setQuery(QueryBuilders.queryStringQuery("name:book_1?1 || color:B*")) // OR与||等价 //.setQuery(QueryBuilders.queryStringQuery("price:[990 TO *]")) // 范围查询 // 默认情况下操作符都是可选的,有两个特殊的->首选操作符是:+(这一项必须存在)和-(这一项必须不存在) .setQuery(QueryBuilders.queryStringQuery("price:[990 TO *] -book*")) // 不显示book*的数据 .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"name":"法拉利LaFerrari","price":"2250.00万","postDate":"2018-12-12T08:38:09.129Z"} {"name":"法拉利488","price":"315.50-418.80万","postDate":"2018-12-12T08:38:09.107Z"} {"name":"Aventador","price":"630.00-755.94万","postDate":"2018-12-12T08:49:01.736Z","extra":"Extra Data"} 命中:3
16.2.5 Simple Query String Query(查询永远不会抛出异常,并丢弃查询的无效部分)
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("book") // + 表示与操作 // | 表示或操作 // - 表示否定 // * 在关键字末尾表示前缀查询 // 小括号()表示优先级 // 这里通配符失效!!比如book_1?1或者book_1*1只会查出一条记录 .setQuery(QueryBuilders.simpleQueryStringQuery("book_11*") // .flags(SimpleQueryStringFlag.AND,SimpleQueryStringFlag.OR,SimpleQueryStringFlag.NOT) // 指定启用哪些解析功能,默认全部启用ALL。SimpleQueryStringFlag ) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
这个功能感觉有点鸡肋,不如QueryStringQuery
执行结果:
{"name":"book_110","price":562.7866825701938,"postDate":"2018-12-12T09:27:32.424Z"} {"name":"book_116","price":764.6107139750268,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_119","price":612.4310597411385,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_113","price":693.0418946151275,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_117","price":955.1701411798869,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_114","price":255.65009974873198,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_118","price":915.8228473795552,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_111","price":185.85669328040666,"postDate":"2018-12-12T09:27:32.424Z"} {"name":"book_112","price":8.035476335226166,"postDate":"2018-12-12T09:27:32.424Z"} {"name":"book_115","price":651.4301559069825,"postDate":"2018-12-12T09:27:32.425Z"} {"name":"book_11","price":365.2274741512962,"postDate":"2018-12-12T09:27:30.720Z"} 命中:11
16.3 Term level queries【查询通常用于数字、日期和枚举等结构化数据,而不是全文字段。或者,它们允许您在分析过程之前处理低级查询】
造一些结构化数据
/** * 准备结构化数据 * @return * @throws IOException */ public static TransportClient structuredData() throws IOException { TransportClient client = TransportClientFactory.getInstance().getClient(); AdminClient admin = client.admin(); IndicesAdminClient indicesAdminClient = admin.indices(); // 指数管理 CreateIndexResponse createIndexResponse = indicesAdminClient.prepareCreate("school") .setSettings(Settings.builder() .put("index.number_of_shards", 1) // 分片 .put("index.number_of_replicas", 1) // 副本 ) .addMapping("student", "sName", "type=text", "sAge", "type=integer", "sClass", "type=keyword", "sTime", "type=date") // mapping .get(); System.out.println("创建索引:" + createIndexResponse.isAcknowledged()); BulkProcessor bulkProcessor = BulkProcessor.builder( client, new BulkProcessor.Listener() { @Override public void beforeBulk(long executionId, BulkRequest request) { // bulk 执行之前 System.out.println("beforeBulk-----" + request.getDescription()); } @Override public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { // bulk 执行之后 System.out.println("afterBulk------" + request.getDescription() + ",是否有错误:" + response.hasFailures()); } @Override public void afterBulk(long executionId, BulkRequest request, Throwable failure) { //bulk 失败 System.out.println("报错-----" + request.getDescription() + "," + failure.getMessage()); } }) .setBulkActions(300) // 每300个request,bulk一次 .setConcurrentRequests(0) // 设置并发请求的数量。值为0意味着只允许执行一个请求。值为1意味着在积累新的批量请求时允许执行1个并发请求。 .build(); Random random = new Random(); for (int i = 1; i <= 1000; i++){ bulkProcessor.add(new IndexRequest("school", "student", i+"").source(jsonBuilder() .startObject() .field("sName", "Student_" + i) .field("sAge", random.nextInt(100)) .field("sClass", "Class_" + (i % 20)) .field("sTime", new Date()) .endObject())); } bulkProcessor.flush(); bulkProcessor.close(); return client; }
查看索引数据:GET /school/_search
注意我这里面有大写字母
查看索引信息:GET /school
16.3.1 Term Query
这里有很多彩蛋~
正确写法:
下面我们查询class字段
正确写法:
代码:
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") //.setQuery(QueryBuilders.termQuery("sName", "student_1")) // 使用term查询类型为text的字段的时候,内容要全部小写 .setQuery(QueryBuilders.termQuery("sClass", "Class_2")) // 使用term查询类型为keyword的字段的时候,内容区分大小写 .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
为什么会出现上述彩蛋呢?
类型为test,会解析其中的内容,比如 "Hey Guy",倒排索引会包括以下术语[hey,guy]
类型为keyword,在倒排索引中会出现以下术语[Hey Guy]
所以,查询全文字段就用match,因为它知道如何分析,term比较傻,只知道精确值,擅长结构化的字段。
16.3.2 TermsQuery
多个查询关键字
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") // 一个字段,多个value .setQuery(QueryBuilders.termsQuery("sName","student_1","student_2")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"sName":"Student_1","sAge":28,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.666Z"} {"sName":"Student_2","sAge":20,"sClass":"Class_2","sTime":"2018-12-13T08:39:57.689Z"} 命中:2
16.3.3 RangeQuery 范围查询
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") .setQuery(QueryBuilders.rangeQuery("sAge") // .gte(10) // 大于等于 // .gt(10) // 大于 // .lte(20) // 小于等于 // .lt(20) // 小于 .from(0) .to(5) .includeLower(true) // 包含下限 .includeUpper(true) // 包含上限 ) // .setQuery(QueryBuilders.rangeQuery("sTime") // .lte("now") // 小于等于当前时间 // .timeZone("-01:00")) // 时区 .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
...省略 {"sName":"Student_340","sAge":5,"sClass":"Class_0","sTime":"2018-12-13T08:39:57.821Z"} {"sName":"Student_372","sAge":1,"sClass":"Class_12","sTime":"2018-12-13T08:39:57.822Z"} {"sName":"Student_428","sAge":2,"sClass":"Class_8","sTime":"2018-12-13T08:39:57.823Z"} {"sName":"Student_432","sAge":0,"sClass":"Class_12","sTime":"2018-12-13T08:39:57.823Z"} 命中:52
16.3.4 ExistQuery
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") .setQuery(QueryBuilders.existsQuery("sName")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
...省略 {"sName":"Student_18","sAge":72,"sClass":"Class_18","sTime":"2018-12-13T08:39:57.690Z"} {"sName":"Student_19","sAge":43,"sClass":"Class_19","sTime":"2018-12-13T08:39:57.690Z"} {"sName":"Student_20","sAge":93,"sClass":"Class_0","sTime":"2018-12-13T08:39:57.690Z"} 命中:1000
全命中了,什么意思呢?
这个方法的作用:对于某个字段,返回至少含有一个非空值的所有文档 。
套用官方解释,比如:查询user字段,可以返回下面格式的数据【有值,空字符串,长度大于0的数组】
然而下面这些就不行了【null,空数组,非查询字段】
16.3.5 Prefix Query 前缀查询(顾名思义,肯定是把关键字作为前缀啦)
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") .setQuery(QueryBuilders.prefixQuery("sName", "student_19")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"sName":"Student_19","sAge":43,"sClass":"Class_19","sTime":"2018-12-13T08:39:57.690Z"} {"sName":"Student_190","sAge":53,"sClass":"Class_10","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_191","sAge":45,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_192","sAge":2,"sClass":"Class_12","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_193","sAge":9,"sClass":"Class_13","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_194","sAge":67,"sClass":"Class_14","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_195","sAge":62,"sClass":"Class_15","sTime":"2018-12-13T08:39:57.696Z"} {"sName":"Student_196","sAge":77,"sClass":"Class_16","sTime":"2018-12-13T08:39:57.696Z"} {"sName":"Student_197","sAge":82,"sClass":"Class_17","sTime":"2018-12-13T08:39:57.696Z"} {"sName":"Student_198","sAge":38,"sClass":"Class_18","sTime":"2018-12-13T08:39:57.696Z"} {"sName":"Student_199","sAge":50,"sClass":"Class_19","sTime":"2018-12-13T08:39:57.696Z"} 命中:11
16.3.6 Wildcard Query
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") // 支持通配符查询[?,*],不建议以通配符开头,那样会很慢 .setQuery(QueryBuilders.wildcardQuery("sName", "student_1?1")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"sName":"Student_101","sAge":87,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.692Z"} {"sName":"Student_111","sAge":98,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.693Z"} {"sName":"Student_121","sAge":96,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.693Z"} {"sName":"Student_131","sAge":89,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.694Z"} {"sName":"Student_141","sAge":90,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.694Z"} {"sName":"Student_151","sAge":52,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.694Z"} {"sName":"Student_161","sAge":21,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_171","sAge":76,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_181","sAge":18,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_191","sAge":45,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.695Z"} 命中:10
16.3.7 Regexp Query
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") // regexp查询的性能在很大程度上取决于所选择的正则表达式。匹配诸如.*之类的所有内容非常慢。*?+ 主要降低性能 .setQuery(QueryBuilders.regexpQuery("sName", "student_.*0")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
...省略 {"sName":"Student_170","sAge":14,"sClass":"Class_10","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_180","sAge":16,"sClass":"Class_0","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_190","sAge":53,"sClass":"Class_10","sTime":"2018-12-13T08:39:57.695Z"} {"sName":"Student_200","sAge":12,"sClass":"Class_0","sTime":"2018-12-13T08:39:57.696Z"} 命中:100
16.3.8 Fuzzy Query
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") // 模糊查询https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness .setQuery(QueryBuilders.fuzzyQuery("sName", "student_33")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
...省略 {"sName":"Student_83","sAge":94,"sClass":"Class_3","sTime":"2018-12-13T08:39:57.692Z"} {"sName":"Student_93","sAge":88,"sClass":"Class_13","sTime":"2018-12-13T08:39:57.692Z"} {"sName":"Student_133","sAge":34,"sClass":"Class_13","sTime":"2018-12-13T08:39:57.694Z"} {"sName":"Student_233","sAge":90,"sClass":"Class_13","sTime":"2018-12-13T08:39:57.696Z"} 命中:50
16.3.9 Type Query
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") .setQuery(QueryBuilders.typeQuery("student")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
就是查询type下的内容..
...省略 {"sName":"Student_18","sAge":72,"sClass":"Class_18","sTime":"2018-12-13T08:39:57.690Z"} {"sName":"Student_19","sAge":43,"sClass":"Class_19","sTime":"2018-12-13T08:39:57.690Z"} {"sName":"Student_20","sAge":93,"sClass":"Class_0","sTime":"2018-12-13T08:39:57.690Z"} 命中:1000
16.3.10 Ids Query
public static TransportClient queryDSL() throws UnknownHostException { TransportClient client = TransportClientFactory.getInstance().getClient(); SearchResponse searchResponse = client.prepareSearch() .setIndices("school") // 根据多个id查询 .setQuery(QueryBuilders.idsQuery("student").addIds("1","111","999")) .setSize(20) // 返回数量 .get(); searchResponse.getHits().forEach(e -> { System.out.println(e.getSourceAsString()); }); System.out.println("命中:" + searchResponse.getHits().totalHits); return client; }
执行结果:
{"sName":"Student_1","sAge":28,"sClass":"Class_1","sTime":"2018-12-13T08:39:57.666Z"} {"sName":"Student_111","sAge":98,"sClass":"Class_11","sTime":"2018-12-13T08:39:57.693Z"} {"sName":"Student_999","sAge":6,"sClass":"Class_19","sTime":"2018-12-13T08:39:58.120Z"} 命中:3
17. Compound queries
..待续