SpringBoot集成ElasticSearch
序言
本章需要你在掌握基本的SpringBoot、JPA和一些ElasticSearch(以下简称:“Es”)的知识下进行服用。
环境
SpringBoot :2.2.6.RELEASE
Es:6.8.7(集群-3节点,且安装了ik分词器)
kibana 6.8.7
说明
测试环境的Es是6.8.7的3节点,代码相关依赖也是和Es服务端保持一致。当然大版本的6和7 Es的Api还是有些区别,具体Api的使用可以去官网进行翻阅,这里是以6.8版本进行讲解。
开始搭建
基本依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
yml配置
server:
port: 8801
spring:
application:
name: esSpringboot
elasticsearch:
rest:
uris: 192.168.1.195:9200,192.168.1.195:9201,192.168.1.195:9202 #设置集群
如何使用
实体
@Document(indexName ="student",type ="_doc",replicas =0,shards =3)@Data@Builder@AllArgsConstructor@NoArgsConstructorpublicclassStudentimplementsSerializable{privatestaticfinallong serialVersionUID =-1479160581341748052L;/*ik_smart 粗精度,ik_max_word 细精度*/@Field(type =FieldType.Text,searchAnalyzer ="ik_smart",analyzer ="ik_max_word")privateString name;/*text类型开启统计的时候需要设置属性fielddata = true 正排索引*/@Field(type =FieldType.Long)privateInteger age;@Field(type =FieldType.Text)privateString testNumber;@Id@Field(type =FieldType.Keyword)privateString id;@Field(type =FieldType.Keyword)privateString email;@Field(type =FieldType.Date,format =DateFormat.custom,pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(shape =JsonFormat.Shape.STRING,pattern ="yyyy-MM-dd HH:mm:ss",timezone ="GMT+8")privateDate birthDay;}
这里需要你已经掌握Es的常用数据类型。
使用Repository
@RepositorypublicinterfaceStudentRepositoryextendsElasticsearchRepository<Student,String>{}
测试
批量添加
public String saveBatch(){
Faker faker = new Faker(Locale.CHINA);
List<Student> collect = Stream.generate(() -> Student.builder()
.age(faker.random().nextInt(1, 100))
.email(faker.internet().emailAddress())
.name(faker.name().username())
.testNumber(faker.random().nextInt(1, 100)+"")
.birthDay(new Date())
.build()
).limit(1000).collect(Collectors.toList());
studentRepository.saveAll(collect);
return "ok";
}
添加完成后我们在对应的kibana上面可以看到对应的Student索引和数据
执行指令查看添加数据的结果
POST/student/_search
{"query":{"match_all":{}}}
结果
根据id查询
publicStudentgetById(Long id){Optional<Student> byId = studentRepository.findById(id +"");return byId.get();}
根据id删除
publicStringremoveById(Long id){
studentRepository.deleteById(id +"");return"ok";}
当然也可以在Repository写一些Es的DSL查询语句
使用DSL
使用@Query 注解
@Query("{\n"+" \"term\": {\n"+" \"name.keyword\": \"?0\"\n"+" }\n"+" }")List<Student>findStudentByName(String name);
复杂查询
- 分页
- 布尔
- term
- multiMatch
- matchPhrase
- fuzzy
- regep
- range
Pageable pageable =PageRequest.of(0,5);//分页BoolQueryBuilder boolQuery=boolQuery()/*term查询*/// .must(QueryBuilders.termQuery("name", student.getName()))/*range查询*/.must(QueryBuilders.rangeQuery("age").gte(0).lte(100))/*multiMatch*/// .must(QueryBuilders.multiMatchQuery(student.getEmail(), "name","email" ).operator(Operator.OR))/*matchPhraseQuery :紧邻查询,slop:允许间隔的单词个数*/// .must(QueryBuilders.matchPhraseQuery("name",student.getName()).slop(1))/*模糊匹配:查询的词也会分词 https://blog.csdn.net/weixin_42692506/article/details/101555035*/// .must(QueryBuilders.fuzzyQuery("name", "21").fuzziness(Fuzziness.AUTO))/*正则查询 [1-9] https://blog.csdn.net/u010483897/article/details/90485332*/// .must(QueryBuilders.regexpQuery("name", student.getName()));SearchQuery searchQuery =newNativeSearchQueryBuilder().withPageable(pageable).withQuery(boolQuery).build();Page<Student> search = studentRepository.search(searchQuery);List<Student> result= search.getContent();
聚合
- 平均值
- 求和
- 最大值
- 最小值
- 范围
- 时间范围
- 时间间隔
- 数值范围
SearchQuery searchQuery = new NativeSearchQueryBuilder()
/*name:统计的名称,field:统计的字段*/
.addAggregation(AggregationBuilders.avg("ageAvg").field("age"))//平均值
.addAggregation(AggregationBuilders.sum("ageSum").field("age"))//求和
.addAggregation(AggregationBuilders.count("ageCount").field("age"))//有age的数目
.addAggregation(AggregationBuilders.max("ageMax").field("age"))//最大值
.addAggregation(AggregationBuilders.min("ageMin").field("age"))//最小值
.addAggregation(AggregationBuilders.percentiles("agePercentiles").field("age"))//年龄百分比
.addAggregation(AggregationBuilders.cardinality("ageCardinality").field("age"))//去重统计有多少数量
.addAggregation(AggregationBuilders.terms("ageTerms").field("age").size(Integer.MAX_VALUE))//统计有相同age
.addAggregation(AggregationBuilders.range("ageRange").field("age").addRange(0, 20)
.addRange(20, 40)
.addRange(40, 60)
.addRange(60, 80)
)//查询年龄20~40,40~60,60~80范围统计
.addAggregation(AggregationBuilders.dateRange("birthDayDateRange").field("birthDay").addRange("now/y-1y", "now/y") // now/y:当前年的1月1日 now:当前时间
.addRange("now/y-2y", "now/y-1y") // now/y-1y:当前年上一年的1月1日
.addRange("now/y-3y", "now/y-2y")
.format("yyyy-MM-dd"))//根据年统计
/*年龄间隔统计 开始如果为20则后续设置统计就是20 22 24 26 28 30*/
.addAggregation(AggregationBuilders.histogram("age_histogram_count")
.field("age")
.interval(20))
/*时间统计 一定是对时间字段的统计,format是设置返回的key按照什么时间格式返回
* 同时统计对应时间的年龄值合计
* */
.addAggregation(AggregationBuilders.dateHistogram("ageDateHistogram")
.field("birthDay")
.dateHistogramInterval(DateHistogramInterval.YEAR)
.format("yyyy-MM-dd HH:mm:ss")
.subAggregation(AggregationBuilders.sum("ageDateHistogramSum").field("age"))
)
AggregatedPage<Student> search = (AggregatedPage<Student>) studentRepository.search(searchQuery);
Aggregations aggregations = search.getAggregations();
Map<String, Aggregation> result= aggregations.getAsMap(); #获取聚合数据
参考
https://www.elastic.co/guide/cn/elasticsearch/guide/current/foreword_id.html
版权归原作者 皮蛋不吃粥 所有, 如有侵权,请联系我们删除。