Elasticsearch 之(43) Java API 实现 ES 的 增删改查、聚合分析
1、maven依赖
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency>
log4j2.properties
appender.console.type = Console appender.console.name = console appender.console.layout.type = PatternLayout rootLogger.level = info rootLogger.appenderRef.console.ref = console2、增删改查
package com.es.app; import java.net.InetAddress; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.transport.client.PreBuiltTransportClient; /** * 员工增删改查的应用程序 * @author Administrator * */ public class EmployeeCRUDApp { @SuppressWarnings({ "unchecked", "resource" }) public static void main(String[] args) throws Exception { // 先构建client Settings settings = Settings.builder() .put("cluster.name", "elasticsearch") .build(); TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); // createEmployee(client); // getEmployee(client); // updateEmployee(client); // deleteEmployee(client); client.close(); } /** * 创建员工信息(创建一个document) * @param client */ private static void createEmployee(TransportClient client) throws Exception { IndexResponse response = client.prepareIndex("company", "employee", "1") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "jack") .field("age", 27) .field("position", "technique") .field("country", "china") .field("join_date", "2017-01-01") .field("salary", 10000) .endObject()) .get(); System.out.println(response.getResult()); } /** * 获取员工信息 * @param client * @throws Exception */ private static void getEmployee(TransportClient client) throws Exception { GetResponse response = client.prepareGet("company", "employee", "1").get(); System.out.println(response.getSourceAsString()); } /** * 修改员工信息 * @param client * @throws Exception */ private static void updateEmployee(TransportClient client) throws Exception { UpdateResponse response = client.prepareUpdate("company", "employee", "1") .setDoc(XContentFactory.jsonBuilder() .startObject() .field("position", "technique manager") .endObject()) .get(); System.out.println(response.getResult()); } /** * 删除 员工信息 * @param client * @throws Exception */ private static void deleteEmployee(TransportClient client) throws Exception { DeleteResponse response = client.prepareDelete("company", "employee", "1").get(); System.out.println(response.getResult()); } }
需求:
(1)搜索职位中包含technique的员工
(2)同时要求age在30到40岁之间
(3)分页查询,查找第一页
GET /company/employee/_search { "query": { "bool": { "must": [ { "match": { "position": "technique" } } ], "filter": { "range": { "age": { "gte": 30, "lte": 40 } } } } }, "from": 0, "size": 1 }
一边运行创建document,一边搜索什么都没搜索到????
近实时!!!默认是1秒以后,写入es的数据,才能被搜索到。
package com.es.app; import java.net.InetAddress; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.transport.client.PreBuiltTransportClient; /** * 员工搜索应用程序 * @author Administrator * */ public class EmployeeSearchApp { @SuppressWarnings({ "unchecked", "resource" }) public static void main(String[] args) throws Exception { Settings settings = Settings.builder() .put("cluster.name", "elasticsearch") .build(); TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); // prepareData(client); executeSearch(client); client.close(); } /** * 执行搜索操作 * @param client */ private static void executeSearch(TransportClient client) { SearchResponse response = client.prepareSearch("company") .setTypes("employee") .setQuery(QueryBuilders.matchQuery("position", "technique")) .setPostFilter(QueryBuilders.rangeQuery("age").from(30).to(40)) .setFrom(0).setSize(1) .get(); SearchHit[] searchHits = response.getHits().getHits(); for(int i = 0; i < searchHits.length; i++) { System.out.println(searchHits[i].getSourceAsString()); } } /** * 准备数据 * @param client */ private static void prepareData(TransportClient client) throws Exception { client.prepareIndex("company", "employee", "1") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "jack") .field("age", 27) .field("position", "technique software") .field("country", "china") .field("join_date", "2017-01-01") .field("salary", 10000) .endObject()) .get(); client.prepareIndex("company", "employee", "2") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "marry") .field("age", 35) .field("position", "technique manager") .field("country", "china") .field("join_date", "2017-01-01") .field("salary", 12000) .endObject()) .get(); client.prepareIndex("company", "employee", "3") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "tom") .field("age", 32) .field("position", "senior technique software") .field("country", "china") .field("join_date", "2016-01-01") .field("salary", 11000) .endObject()) .get(); client.prepareIndex("company", "employee", "4") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "jen") .field("age", 25) .field("position", "junior finance") .field("country", "usa") .field("join_date", "2016-01-01") .field("salary", 7000) .endObject()) .get(); client.prepareIndex("company", "employee", "5") .setSource(XContentFactory.jsonBuilder() .startObject() .field("name", "mike") .field("age", 37) .field("position", "finance manager") .field("country", "usa") .field("join_date", "2015-01-01") .field("salary", 15000) .endObject()) .get(); } }
需求:
(1)首先按照country国家来进行分组
(2)然后在每个country分组内,再按照入职年限进行分组
(3)最后计算每个分组内的平均薪资
package com.es.app; import java.net.InetAddress; import java.util.Iterator; import java.util.Map; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket; import org.elasticsearch.search.aggregations.metrics.avg.Avg; import org.elasticsearch.transport.client.PreBuiltTransportClient; /** * 员工聚合分析应用程序 * @author Administrator * */ public class EmployeeAggrApp { @SuppressWarnings({ "unchecked", "resource" }) public static void main(String[] args) throws Exception { Settings settings = Settings.builder() .put("cluster.name", "elasticsearch") .build(); TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); SearchResponse searchResponse = client.prepareSearch("company") .addAggregation(AggregationBuilders.terms("group_by_country").field("country") .subAggregation(AggregationBuilders .dateHistogram("group_by_join_date") .field("join_date") .dateHistogramInterval(DateHistogramInterval.YEAR) .subAggregation(AggregationBuilders.avg("avg_salary").field("salary"))) ) .execute().actionGet(); Map<String, Aggregation> aggrMap = searchResponse.getAggregations().asMap(); StringTerms groupByCountry = (StringTerms) aggrMap.get("group_by_country"); Iterator<Bucket> groupByCountryBucketIterator = groupByCountry.getBuckets().iterator(); while(groupByCountryBucketIterator.hasNext()) { Bucket groupByCountryBucket = groupByCountryBucketIterator.next(); System.out.println(groupByCountryBucket.getKey() + ":" + groupByCountryBucket.getDocCount()); Histogram groupByJoinDate = (Histogram) groupByCountryBucket.getAggregations().asMap().get("group_by_join_date"); Iterator<org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Bucket> groupByJoinDateBucketIterator = groupByJoinDate.getBuckets().iterator(); while(groupByJoinDateBucketIterator.hasNext()) { org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Bucket groupByJoinDateBucket = groupByJoinDateBucketIterator.next(); System.out.println(groupByJoinDateBucket.getKey() + ":" +groupByJoinDateBucket.getDocCount()); Avg avg = (Avg) groupByJoinDateBucket.getAggregations().asMap().get("avg_salary"); System.out.println(avg.getValue()); } } client.close(); } }
正排索引没开启时候,会报错:
Exception in thread "main" Failed to execute phase [query], all shards failed; shardFailures {[yLv8gDZQQ5eMlHYMN0lKTg][company][0]: RemoteTransportException[[yLv8gDZ][127.0.0.1:9300][indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [country] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.]; }{[yLv8gDZQQ5eMlHYMN0lKTg][company][1]: RemoteTransportException[[yLv8gDZ][127.0.0.1:9300][indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [country] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.]; }{[yLv8gDZQQ5eMlHYMN0lKTg][company][2]: RemoteTransportException[[yLv8gDZ][127.0.0.1:9300][indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [country] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.]; }{[yLv8gDZQQ5eMlHYMN0lKTg][company][3]: RemoteTransportException[[yLv8gDZ][127.0.0.1:9300][indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [country] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.]; }{[yLv8gDZQQ5eMlHYMN0lKTg][company][4]: RemoteTransportException[[yLv8gDZ][127.0.0.1:9300][indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Fielddata is disabled on text fields by default. Set fielddata=true on [country] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.]; }重新构建mapping
GET /company/_mapping/employee DELETE /company PUT /company { "mappings": { "employee": { "properties": { "age": { "type": "long" }, "country": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } }, "fielddata": true }, "join_date": { "type": "date" }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "position": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "salary": { "type": "long" } } } } }