一、背景
最近在学习 es 和 java 的整合,整合过程中发现一些查询语句不知道怎么用 java 写,网上也查不到比较全面的,所以就自己整理了下,便于后续查阅。
二、准备环境
2.1 环境信息
框架 | 版本号 | 备注 |
---|---|---|
springboot | 2.2.6.RELEASE | |
Elasticsearch | 7.1.0 | 单机,非集群 |
2.2 搭建 springboot 环境
maven 配置中需要引入以下 jar 包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
复制代码
2.3 新增 es 配置文件
/**
* es 配置文件
*
* @author liuqiuyi
* @date 2021/4/19 23:06
*/
@Configuration
public class TransportClientConfig extends ElasticsearchConfigurationSupport {
@Bean
public Client elasticsearchClient() throws UnknownHostException {
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings);
// 注意端口为 9300
client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
return client;
}
@Bean(name = {"elasticsearchOperations", "elasticsearchTemplate"})
public ElasticsearchTemplate elasticsearchTemplate() throws UnknownHostException {
return new ElasticsearchTemplate(elasticsearchClient(), entityMapper());
}
}
复制代码
三、使用示例
3.1 增、删、改 语句
- 新建 java bean
/**
* es 测试对象类
* @author liuqiuyi
* @date 2021/4/22 20:38
*/
@Data
@Document(indexName = "employee", type = "_doc")
public class Employee implements Serializable {
private static final long serialVersionUID = 813700671392848305L;
private Long id;
private String name;
private String job;
private Integer age;
private String gender;
public Employee(Long id, String name, String job, Integer age, String gender) {
this.id = id;
this.name = name;
this.job = job;
this.age = age;
this.gender = gender;
}
public Employee() {
}
}
复制代码
- 新建测试类
/**
* 增 删 改 测试
*
* @author liuqiuyi
* @date 2021/4/28 20:47
*/
public class CrudTest extends UtilsApplicationTests {
@Resource
ElasticsearchTemplate elasticsearchTemplate;
/**
* 单个保存 or 更新
*
* id 不存在,保存
* id 已经存在,更新
*
* @author liuqiuyi
* @date 2021/4/28 20:48
*/
@Test
public void saveOrUpdateTest() {
Employee employee = new Employee(17L, "liuqiuyi", "全栈", 25, "男");
IndexQuery indexQuery = new IndexQueryBuilder()
.withObject(employee)
.build();
String index = elasticsearchTemplate.index(indexQuery);
// 返回的 index 是数据 id,如果指定了,返回指定的 id 值,未指定,返回一个 es 自动生成的
System.out.println(index);
}
/**
* 批量保存
*
* @author liuqiuyi
* @date 2021/4/29 19:53
*/
@Test
public void batchSaveTest() {
Employee employeeA = new Employee(18L, "liuqiuyi", "java", 25, "男");
Employee employeeB = new Employee(19L, "liuqiuyi", "java", 25, "男");
ArrayList<Employee> employeeArrayList = Lists.newArrayList(employeeA, employeeB);
List<IndexQuery> indexQueryList = Lists.newArrayList();
for (Employee employee : employeeArrayList) {
IndexQuery indexQuery = new IndexQueryBuilder()
.withObject(employee)
.build();
indexQueryList.add(indexQuery);
}
elasticsearchTemplate.bulkIndex(indexQueryList);
}
/**
* 根据 id 单个删除
*
* @author liuqiuyi
* @date 2021/4/29 20:30
*/
@Test
public void deleteByIdTest(){
String delete = elasticsearchTemplate.delete(Employee.class, "79R2HXkBm5pjjA5okt3o");
System.out.println(delete);
}
/**
* 批量删除
*
* @author liuqiuyi
* @date 2021/5/6 15:37
*/
@Test
public void batchDeleteByIdsTest(){
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria());
criteriaQuery.setIds(Lists.newArrayList("18", "19"));
elasticsearchTemplate.delete(criteriaQuery, Employee.class);
}
}
复制代码
3.2 简单 DSL 查询
3.2.1 导入测试数据
- 使用 logstash 导入,具体操作方式见附录
3.2.2 新建 java bean
/**
* ES 测试对象
* 需要添加 @Document,指定索引名称和 type(es 7之后是固定值)
*
* @author liuqiuyi
* @date 2021/4/19 23:37
*/
@Data
@Document(indexName = "movies", type = "_doc")
public class Movies implements Serializable {
private static final long serialVersionUID = -343559824622431609L;
private String id;
private String title;
private String[] genre;
private Long year;
}
复制代码
3.2.3 查询示例
/**
* 简单 DSL 查询
*
* @author liuqiuyi
* @date 2021/4/22 20:32
*/
public class SimpleQueryTest extends UtilsApplicationTests {
@Resource
ElasticsearchTemplate elasticsearchTemplate;
/**
* GET movies/_search
* {
* "query": {
* "term": {
* "title": {
* "value": "beautiful"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 16:47
*/
@Test
public void termTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(termQuery("title", "beautiful"))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "terms": {
* "title": [
* "beautiful",
* "mind"
* ]
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 16:53
*/
@Test
public void termsTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(termsQuery("title", "beautiful","mind"))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "range": {
* "year": {
* "gte": 2016,
* "lte": 2018
* }
* }
* },
* "sort": [
* {
* "year": {
* "order": "desc"
* }
* }
* ]
* }
*
* @author liuqiuyi
* @date 2021/4/21 16:57
*/
@Test
public void rangeTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(rangeQuery("year").gte(2016).lte(2018))
.withSort(fieldSort("year").order(SortOrder.DESC))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "constant_score": {
* "filter": {
* "term": {
* "title": "beautiful"
* }
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:02
*/
@Test
public void constant_scoreTest()
{
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(constantScoreQuery(QueryBuilders.termQuery("title","beautiful")))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "match": {
* "title": "beautiful"
* }
* },
* "from": 10,
* "size": 10
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:06
*/
@Test
public void matchTest() {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "beautiful"))
// es 的分页,默认是从 0 开始的
.withPageable(PageRequest.of(1, 10)).build();
AggregatedPage<Movies> queryForPage = elasticsearchTemplate.queryForPage(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(queryForPage.getContent()));
}
/**
* GET movies/_search
* {
* "_source": [
* "title",
* "id"
* ],
* "query": {
* "match": {
* "title": "beautiful mind"
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:13
*/
@Test
public void match_sourceTest() {
String[] includes = new String[]{"title", "id"};
FetchSourceFilter sourceFilter = new FetchSourceFilter(includes, null);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", "beautiful mind"))
.withSourceFilter(sourceFilter)
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "match_phrase": {
* "title": "beautiful mind"
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:20
*/
@Test
public void match_phraseTest() {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchPhraseQuery("title", "beautiful mind"))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "multi_match": {
* "query": "beautiful Adventure",
* "fields": [
* "title",
* "genre"
* ]
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:22
*/
@Test
public void multi_matchTest() {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(multiMatchQuery("beautiful Adventure", "title", "genre"))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "match_all": {}
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:26
*/
@Test
public void match_allTest() {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "query_string": {
* "default_field": "title",
* "query": "mind beautiful",
* "default_operator": "AND"
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 16:16
*/
@Test
public void query_stringTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryStringQuery("mind beautiful").defaultField("title").defaultOperator(Operator.AND))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "simple_query_string": {
* "query": "beautiful + mind",
* "fields": [
* "title"
* ]
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/21 17:37
*/
@Test
public void simple_query_stringTest(){
Map<String, Float> fields = Maps.newHashMap();
// 不知道这个 value 是什么意思
fields.put("title", 1f);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(simpleQueryStringQuery("mind beautiful").fields(fields).defaultOperator(Operator.AND))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "fuzzy": {
* "title": {
* "value": "neverendign",
* "fuzziness": 1,
* "prefix_length": 5
* }
* }
* }
* }
*
* 查询title中从第6个字母开始只要最多纠正一次,就与 neverendign 匹配的所有的数据
* es中,是从 0 开始计数的,所以这里是 5
* @author liuqiuyi
* @date 2021/4/21 17:47
*/
@Test
public void fuzzyTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(fuzzyQuery("title", "neverendign").fuzziness(Fuzziness.ONE).transpositions(true).prefixLength(5))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "bool": {
* "must": [
* {
* "simple_query_string": {
* "query": "beautiful mind",
* "fields": [
* "title"
* ]
* }
* },
* {
* "range": {
* "year": {
* "gte": 2016,
* "lte": 2018
* }
* }
* }
* ]
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/22 19:19
*/
@Test
public void boolTest(){
Map<String, Float> fields = Maps.newHashMap();
// 不知道这个 value 是什么意思
fields.put("title", 1f);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery().must(simpleQueryStringQuery("beautiful mind").fields(fields)).must(rangeQuery("year").gte(2016).lte(2018)))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
/**
* GET movies/_search
* {
* "query": {
* "bool": {
* "filter": [
* {
* "term": {
* "title": "beautiful"
* }
* },
* {
* "range": {
* "year": {
* "gte": 2016,
* "lte": 2018
* }
* }
* }
* ]
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/22 20:00
*/
@Test
public void boolFilterTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery().filter(termQuery("title", "beautiful")).must(rangeQuery("year").gte(2016).lte(2018)))
.build();
List<Movies> movies = elasticsearchTemplate.queryForList(searchQuery, Movies.class);
System.out.println(JSON.toJSONString(movies));
}
}
复制代码
3.3 聚合查询
/**
* 聚合查询的例子
*
* PUT employee/_bulk
* {"index":{"_id":1}}
* {"id":1,"name":"Bob","job":"java","age":21,"sal":8000,"gender":"female"}
* {"index":{"_id":2}}
* {"id":2,"name":"Rod","job":"html","age":31,"sal":18000,"gender":"female"}
* {"index":{"_id":3}}
* {"id":3,"name":"Gaving","job":"java","age":24,"sal":12000,"gender":"male"}
* {"index":{"_id":4}}
* {"id":4,"name":"King","job":"dba","age":26,"sal":15000,"gender":"female"}
* {"index":{"_id":5}}
* {"id":5,"name":"Jonhson","job":"dba","age":29,"sal":16000,"gender":"male"}
* {"index":{"_id":6}}
* {"id":6,"name":"Douge","job":"java","age":41,"sal":20000,"gender":"female"}
* {"index":{"_id":7}}
* {"id":7,"name":"cutting","job":"dba","age":27,"sal":7000,"gender":"male"}
* {"index":{"_id":8}}
* {"id":8,"name":"Bona","job":"html","age":22,"sal":14000,"gender":"female"}
* {"index":{"_id":9}}
* {"id":9,"name":"Shyon","job":"dba","age":20,"sal":19000,"gender":"female"}
* {"index":{"_id":10}}
* {"id":10,"name":"James","job":"html","age":18,"sal":22000,"gender":"male"}
* {"index":{"_id":11}}
* {"id":11,"name":"Golsling","job":"java","age":32,"sal":23000,"gender":"female"}
* {"index":{"_id":12}}
* {"id":12,"name":"Lily","job":"java","age":24,"sal":2000,"gender":"male"}
* {"index":{"_id":13}}
* {"id":13,"name":"Jack","job":"html","age":23,"sal":3000,"gender":"female"}
* {"index":{"_id":14}}
* {"id":14,"name":"Rose","job":"java","age":36,"sal":6000,"gender":"female"}
* {"index":{"_id":15}}
* {"id":15,"name":"Will","job":"dba","age":38,"sal":4500,"gender":"male"}
* {"index":{"_id":16}}
* {"id":16,"name":"smith","job":"java","age":32,"sal":23000,"gender":"male"}
*
* @author liuqiuyi
* @date 2021/4/22 20:32
*/
public class AggregationQueryTest extends UtilsApplicationTests {
@Resource
ElasticsearchTemplate elasticsearchTemplate;
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "other_info": {
* "sum": {
* "field": "sal"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/22 20:41
*/
@Test
public void sumTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.sum("other_info").field("sal"))
.build();
Double sumResult = elasticsearchTemplate.query(searchQuery, searchResponse -> {
// TODO 这里会将具体的数据返回,目前没找到解决办法
InternalSum internalSum = searchResponse.getAggregations().get("other_info");
return internalSum.value();
});
System.out.println(sumResult);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "other_aggs_info": {
* "avg": {
* "field": "sal"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/23 20:40
*/
@Test
public void avgTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.avg("other_aggs_info").field("sal"))
.build();
Double sumResult = elasticsearchTemplate.query(searchQuery, searchResponse -> {
// TODO 这里会将具体的数据返回,目前没找到解决办法
InternalAvg avg = searchResponse.getAggregations().get("other_aggs_info");
return avg.value();
});
System.out.println(sumResult);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "job_count": {
* "cardinality": {
* "field": "job"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/23 20:45
*/
@Test
public void cardinalityTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.cardinality("job_count").field("job"))
.build();
Double sumResult = elasticsearchTemplate.query(searchQuery, searchResponse -> {
// TODO 这里会将具体的数据返回,目前没找到解决办法
InternalCardinality jobCount = searchResponse.getAggregations().get("job_count");
return jobCount.value();
});
System.out.println(sumResult);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "max_result": {
* "max": {
* "field": "sal"
* }
* },
* "min_result": {
* "min": {
* "field": "sal"
* }
* },
* "avg_result": {
* "avg": {
* "field": "sal"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/23 20:48
*/
@Test
public void multivaluedTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.max("max_result").field("sal"))
.addAggregation(AggregationBuilders.min("min_result").field("sal"))
.addAggregation(AggregationBuilders.avg("avg_result").field("sal"))
.build();
Map<String, Double> resultMap = elasticsearchTemplate.query(searchQuery, searchResponse -> {
Map<String, Double> stringDoubleMap = Maps.newHashMap();
InternalMax maxResult = searchResponse.getAggregations().get("max_result");
InternalMin minResult = searchResponse.getAggregations().get("min_result"
);
InternalAvg avgResult = searchResponse.getAggregations().get("avg_result");
stringDoubleMap.put("max_result", maxResult.value());
stringDoubleMap.put("min_result", minResult.value());
stringDoubleMap.put("avg_result", avgResult.value());
return stringDoubleMap;
});
System.out.println(resultMap);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "sal_info": {
* "stats": {
* "field": "sal"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/25 19:46
*/
@Test
public void statsTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.stats("sal_info").field("sal"))
.build();
Map<String, Object> resultMap = elasticsearchTemplate.query(searchQuery, searchResponse -> {
Map<String, Object> stringDoubleMap = Maps.newHashMap();
InternalStats stats = searchResponse.getAggregations().get("sal_info");
stringDoubleMap.put("count", stats.getCount());
stringDoubleMap.put("min", stats.getMin());
stringDoubleMap.put("max", stats.getMax());
stringDoubleMap.put("avg", stats.getAvg());
stringDoubleMap.put("sum", stats.getSum());
return stringDoubleMap;
});
System.out.println(resultMap);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "job_count": {
* "terms": {
* "field": "job"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/25 20:18
*/
@Test
public void termsTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.terms("job_count").field("job"))
.build();
Map<Object, Object> resultMap = elasticsearchTemplate.query(searchQuery, searchResponse -> {
Map<Object, Object> objectObjectMap = Maps.newHashMap();
Terms terms = searchResponse.getAggregations().get("job_count");
for (Terms.Bucket bt : terms.getBuckets()) {
Object key = bt.getKey();
long docCount = bt.getDocCount();
objectObjectMap.put(key, docCount);
}
return objectObjectMap;
});
System.out.println(resultMap);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "job_info": {
* "terms": {
* "field": "job"
* },
* "aggs": {
* "sal_info": {
* "stats": {
* "field": "sal"
* }
* }
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/25 20:36
*/
@Test
public void termsAndStatsTest(){
TermsAggregationBuilder jobInfoTerm = AggregationBuilders.terms("job_info").field("job");
StatsAggregationBuilder subTerm = AggregationBuilders.stats("sal_info").field("sal");
jobInfoTerm.subAggregation(subTerm);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(jobInfoTerm)
.build();
Map<Object, Object> resultMap = elasticsearchTemplate.query(searchQuery, searchResponse -> {
Map<Object, Object> objectObjectMap = Maps.newHashMap();
Terms terms = searchResponse.getAggregations().get("job_info");
for (Terms.Bucket bt : terms.getBuckets()) {
Object key = bt.getKey();
long docCount = bt.getDocCount();
objectObjectMap.put(key, docCount);
// 获取子集
InternalStats aggregations = bt.getAggregations().get("sal_info");
// 根据需求自行取值
long count = aggregations.getCount();
}
return objectObjectMap;
});
System.out.println(resultMap);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "job_info": {
* "terms": {
* "field": "job"
* },
* "aggs": {
* "gender_info": {
* "terms": {
* "field": "gender"
* },
* "aggs": {
* "sal_info": {
* "stats": {
* "field": "sal"
* }
* }
* }
* }
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/25 20:51
*/
@Test
public void multiAggsTest(){
TermsAggregationBuilder jobInfoTerm = AggregationBuilders.terms("job_info").field("job");
TermsAggregationBuilder genderInfoTerm = AggregationBuilders.terms("gender_info").field("gender");
StatsAggregationBuilder subTerm = AggregationBuilders.stats("sal_info").field("sal");
genderInfoTerm.subAggregation(subTerm);
jobInfoTerm.subAggregation(genderInfoTerm);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(jobInfoTerm)
.build();
Map<Object, Object> resultMap = elasticsearchTemplate.query(searchQuery, searchResponse -> {
Map<Object, Object> objectObjectMap = Maps.newHashMap();
Terms terms = searchResponse.getAggregations().get("job_info");
for (Terms.Bucket bt : terms.getBuckets()) {
Object key = bt.getKey();
long docCount = bt.getDocCount();
objectObjectMap.put(key, docCount);
// 获取子集
Terms subTerms = bt.getAggregations().get("gender_info");
for (Terms.Bucket subTermsBucket : subTerms.getBuckets()) {
Object subKey = subTermsBucket.getKey();
long subDocCount = subTermsBucket.getDocCount();
// 获取最里层数据
InternalStats aggregations = subTermsBucket.getAggregations().get("sal_info");
// 根据需求自行取值
// 打印结果,测试用
System.out.println(subKey + "_" + subDocCount + "_" + JSON.toJSONString(aggregations));
}
}
return objectObjectMap;
});
System.out.println(resultMap);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "top_age_2": {
* "top_hits": {
* "size": 2,
* "sort": [
* {
* "age": {
* "order": "desc"
* }
* }
* ]
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/26 20:29
*/
@Test
public void TopHitsTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes(
"_doc")
.addAggregation(AggregationBuilders.topHits("top_age_2").size(2))
.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC))
.build();
List<Employee> resultList = elasticsearchTemplate.query(searchQuery, searchResponse -> {
List<Employee> employeeList = Lists.newArrayList();
InternalTopHits hits = searchResponse.getAggregations().get("top_age_2");
SearchHit[] subHits = hits.getHits().getHits();
for (SearchHit subHit : subHits) {
// TODO 这里使用了 JSONString to Object
String sourceAsString = subHit.getSourceAsString();
Employee employee = JSON.parseObject(sourceAsString, Employee.class);
employeeList.add(employee);
}
return employeeList;
});
System.out.println(resultList);
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "sal_info": {
* "range": {
* "field": "sal",
* "ranges": [
* {
* "key": "0 <= sal <= 5000",
* "from": 0,
* "to": 5000
* },
* {
* "key": "5001 <= sal <= 10000",
* "from": 5001,
* "to": 10000
* },
* {
* "key": "10001 <= sal <= 15000",
* "from": 10001,
* "to": 15000
* }
* ]
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/27 20:00
*/
@Test
public void rangeTest(){
RangeAggregationBuilder rangeAggregationBuilder = AggregationBuilders.range("sal_info").field("sal")
.addRange("0 <= sal <= 5000", 0d, 5000d)
.addRange("5001 <= sal <= 10000", 5001d, 10000d)
.addRange("10001 <= sal <= 15000", 10001d, 15000d);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(rangeAggregationBuilder)
.build();
List<Long> resultList = elasticsearchTemplate.query(searchQuery, searchResponse -> {
List<Long> docCountList = Lists.newArrayList();
Range range = searchResponse.getAggregations().get("sal_info");
for (Range.Bucket bucket : range.getBuckets()) {
long docCount = bucket.getDocCount();
docCountList.add(docCount);
}
return docCountList;
});
System.out.println(JSON.toJSONString(resultList));
}
/**
* GET employee/_search
* {
* "size": 0,
* "aggs": {
* "sal_info": {
* "histogram": {
* "field": "sal",
* "interval": 5000,
* "extended_bounds": {
* "min": 0,
* "max": 30000
* }
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/27 20:29
*/
@Test
public void histogramTest(){
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("employee").withTypes("_doc")
.addAggregation(AggregationBuilders.histogram("sal_info").field("sal").interval(5000d).extendedBounds(0d, 30000d))
.build();
List<Long> resultList = elasticsearchTemplate.query(searchQuery, searchResponse -> {
List<Long> docCountList = Lists.newArrayList();
Histogram histogram = searchResponse.getAggregations().get("sal_info");
for (Histogram.Bucket bucket : histogram.getBuckets()) {
long docCount = bucket.getDocCount();
docCountList.add(docCount);
}
return docCountList;
});
System.out.println(JSON.toJSONString(resultList));
}
}
复制代码
3.4 其它查询
/**
* 其它查询语句
*
* @author liuqiuyi
* @date 2021/4/28 19:56
*/
public class OtherQueryTest extends UtilsApplicationTests {
@Resource
ElasticsearchTemplate elasticsearchTemplate;
/**
* 推荐搜索
*
* GET movies/_search
* {
* "suggest": {
* "title_suggestion": {
* "text": "drema",
* "term": {
* "field": "title",
* "suggest_mode": "popular"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/27 20:48
*/
@Test
public void recommendationTest(){
// 构建 推荐搜索 的条件
TermSuggestionBuilder suggestionBuilder = SuggestBuilders.termSuggestion("title")
.suggestMode(TermSuggestionBuilder.SuggestMode.POPULAR).text("drema");
SearchResponse searchResponse = elasticsearchTemplate.suggest(new SuggestBuilder().addSuggestion("title_suggestion", suggestionBuilder), Movies.class);
// 取值
TermSuggestion termSuggestion = searchResponse.getSuggest().getSuggestion("title_suggestion");
TermSuggestion.Entry options = termSuggestion.getEntries().get(0);
options.forEach(e -> {
Text text = e.getText();
float score = e.getScore();
int freq = e.getFreq();
System.out.println(text.toString() + "-" + score + "-" + freq);
});
}
/**
* 自动补全
*
* PUT articles
* {
* "mappings": {
* "properties": {
* "title_completion":{ // 字段名
* "type": "completion" // 类型
* }
* }
* }
* }
* --------------------------
* POST articles/_bulk
* {"index":{}}
* {"title_completion":"liuqiuyi"}
* {"index":{}}
* {"title_completion":"ls liuqiuyi"}
* {"index":{}}
* {"title_completion":"this is a liuqiuyi"}
* ---------------------------
* POST articles/_search
* {
* "size": 0,
* "suggest": {
* "articles_suggest": {
* "prefix": "l",
* "completion": {
* "field": "title_completion"
* }
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/28 20:20
*/
@Test
public void automaticCompletionTest(){
CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("title_completion").prefix("l");
SearchResponse searchResponse = elasticsearchTemplate.suggest(new SuggestBuilder().addSuggestion("articles_suggest", suggestionBuilder), "articles");
// 取值
CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("articles_suggest");
List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getOptions();
for (CompletionSuggestion.Entry.Option option : options) {
SearchHit hit = option.getHit();
String sourceAsString = hit.getSourceAsString();
System.out.println(sourceAsString);
}
}
/**
* 高亮显示
*
* GET movies/_search
* {
* "query": {
* "match": {
* "title": "beautiful"
* }
* },
* "highlight": {
* "post_tags": "</span>",
* "pre_tags": "<span color='red'>",
* "fields": {
* "title": {}
* }
* }
* }
*
* @author liuqiuyi
* @date 2021/4/28 20:22
*/
@Test
public void highlightTest(){
HighlightBuilder highlightBuilder = new HighlightBuilder().postTags("</span>").preTags("<span color='red'>").field("title");
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("movies").withTypes("_doc")
.withQuery(matchQuery("title", "beautiful"))
.withHighlightBuilder(highlightBuilder)
.build();
elasticsearchTemplate.query(searchQuery, searchResponse -> {
SearchHits hits = searchResponse.getHits();
SearchHit[] resultHits = hits.getHits();
for (SearchHit resultHit : resultHits) {
Map<String, HighlightField> highlightFields = resultHit.getHighlightFields();
for (Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) {
HighlightField value = entry.getValue();
Text[] fragments = value.getFragments();
// 根据业务需要自行取值
System.out.println(entry.getKey() + "-" + fragments[0]);
}
}
return null;
});
}
}
复制代码
四、附录
4.1 使用 logstash 导入数据
- 官网下载 logstash 并解压
- 在 logstash 的 config 目录下,新建一个 logstash.conf 文件,内容如下:
input {
file {
# 数据文件的目录
path => "/Users/liuqiuyi/Desktop/myWorkSpace/utils/docker/logstash-7.1.0/cvs/movies.csv"
start_position => "beginning"
# 监听文件读取的日志记录,如果第一次导入失败,记得删除掉这个日志,在进行第二次导入
sincedb_path => "/Users/liuqiuyi/Desktop/myWorkSpace/utils/docker/logstash-7.1.0/logs/db_path.log"
}
}
filter {
csv {
separator => ","
columns => ["id","content","genre"]
}
mutate {
split => { "genre" => "|" }
remove_field => ["path", "host","@timestamp","message"]
}
mutate {
split => ["content", "("]
add_field => { "title" => "%{[content][0]}"}
add_field => { "year" => "%{[content][1]}"}
}
mutate {
convert => {
"year" => "integer"
}
strip => ["title"]
remove_field => ["path", "host","@timestamp","message","content"]
}
}
output {
elasticsearch {
# 指定 es 地址
hosts => "http://localhost:9200"
# 指定索引名
index => "movies"
document_id => "%{id}"
}
stdout {}
}
复制代码
- 开始导入,执行以下命令
./bin/logstash -f ./config/logstash.conf
复制代码
- movies 文件下载链接: pan.baidu.com/s/1Fp0XCNFA… 密码: p40r