ElasticSearch-Springboot-Data使用
之前说过ElasticSearch一共支持4种Api,本篇文章主要讲解Springboot数据层集成ElasticSearch的Api简单使用。先看看下面这个Spring集成数据层框架图

可以看到Spring Data系列集成了非常多数据层框架,JDBC,Redis,ElasticSearch,Hadoop,Solr,MongoDB等,非常多啊,感觉spring是要一统天下啊,多的不说了,看看我们这个es怎么做
注意:我这里es的版本是5.6.2,由于es官方更新较快(现在已经7.15),相关api的使用,内部方法也在变,所以别的版本可能会有些变化
1.创建springboot项目,导入相关依赖
首先parent父工程,我这里是2.0.5版本,对应里面的es版本刚好是5.x版本,如果不一样,需改变版本
1 2 3 4 5
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> </parent>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.15</version> </dependency> </dependencies>
|
2.创建好启动类(不做演示),以及yaml配置文件
1 2 3 4 5
| spring: data: elasticsearch: cluster-name: elasticsearch cluster-nodes: 127.0.0.1:9300
|
3.创建实体类,做es的文档对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Data @AllArgsConstructor @NoArgsConstructor @Document(indexName = "student",type = "infro") public class Student { @Id private Long id;
@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word") private String sname;
@Field(type = FieldType.Keyword) private int sage;
@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word") private String intro; }
|
@Document(indexName = “student”,type = “infro”)
indexName:指定索引名
type:指定类型名
@Id:代表文档id
@Field(type = FieldType.Text,analyzer = “ik_max_word”,searchAnalyzer = “ik_max_word”)
type:自定该字段的类型(Text和KeyWord都是String类型,Text代表分词,KeyWord代表不分词)
analyzer:指定存储时使用什么分词策略
searchAnalyzer:指定搜索时使用什么分词策略
4.创建索引测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RunWith(SpringRunner.class) @SpringBootTest(classes = ESApp.class) public class EsIndexTest { @Autowired private ElasticsearchTemplate elasticsearchTemplate;
@Test public void testCreateIndex(){ elasticsearchTemplate.createIndex(Student.class); elasticsearchTemplate.putMapping(Student.class); } }
|
5.创建文档测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @RunWith(SpringRunner.class) @SpringBootTest(classes = ESApp.class) public class EsSimpleDocTest {
@Autowired private EsRepository esRepository;
@Test public void testAddDoc(){ Student student = new Student(1L, "zhangsan", 18, "法外狂徒张三"); esRepository.save(student); } @Test public void testUpdateDoc(){ Student student = new Student(1L, "lisi", 20, "法外狂徒李四"); esRepository.save(student); } @Test public void testDelDoc(){ esRepository.deleteById(1L); } @Test public void testSearchDoc(){ Iterable<Student> students = esRepository.findAll(); students.forEach(student -> { System.out.println(student); }); System.out.println("============="); Optional<Student> studentOptional = esRepository.findById(1L); Student student = studentOptional.get(); System.out.println(student); }
@Test public void testAddMutilDoc(){ ArrayList<Student> students = new ArrayList<>(); students.add(new Student(1L,"zhangsan",18,"法外狂徒张三")); students.add(new Student(2L,"lisi",20,"那真是绝了")); students.add(new Student(3L,"王五",28,"法外狂徒张三")); students.add(new Student(4L,"周勇",30,"不会吧")); students.add(new Student(5L,"何总",25,"可恶")); students.add(new Student(6L,"lisi",18,"秀儿")); esRepository.saveAll(students); } }
|
6.文档高级搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| @RunWith(SpringRunner.class) @SpringBootTest(classes = ESApp.class) public class EsMutilSearchDocTest { @Autowired private EsRepository esRepository;
@Test public void testMutilSearch(){ NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.must(QueryBuilders.matchQuery("sname","lisi")); boolQueryBuilder.filter(QueryBuilders.rangeQuery("sage").gte(18).lte(30)); builder.withQuery(boolQueryBuilder);
builder.withSort(new FieldSortBuilder("sage").order(SortOrder.ASC));
builder.withPageable(PageRequest.of(0,10));
NativeSearchQuery searchQuery = builder.build();
Page<Student> studentPage = esRepository.search(searchQuery); System.out.println(studentPage.getTotalElements()); System.out.println(studentPage.getTotalPages());
List<Student> students = studentPage.getContent(); students.forEach(student -> { System.out.println(student); }); } }
|
7.文档高亮搜素
7.1SpringbootData中没有对高亮结果处理,所以要自己写结果处理器,并交给spring管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @Component public class HighlightResultMapper implements SearchResultMapper {
@Override public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) { long totalHits = response.getHits().getTotalHits(); List<T> list = Lists.newArrayList(); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { if(hits.getHits().length <= 0){ return null; } Map<String, Object> map = hit.getSourceAsMap(); Map<String, HighlightField> highlightFields = hit.getHighlightFields(); for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) { String key = highlightField.getKey(); HighlightField value = highlightField.getValue(); Text[] fragments = value.getFragments(); StringBuilder sb = new StringBuilder(); for (Text text : fragments) { sb.append(text); } map.put(key, sb.toString()); } T item = JSON.parseObject(JSONObject.toJSONString(map),aClass); list.add(item); } return new AggregatedPageImpl<>(list, pageable, totalHits); }
}
|
7.2文档高亮测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @RunWith(SpringRunner.class) @SpringBootTest(classes = ESApp.class) public class EsHighlightMutilSearchTest { @Autowired private ElasticsearchTemplate elasticsearchTemplate;
@Autowired private HighlightResultMapper highlightResultMapper;
@Test public void testHighlightSearch(){ NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder(); searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery()); HighlightBuilder.Field highlightBuilder = new HighlightBuilder.Field("sname").preTags("<font color='red'>").postTags("</font>"); searchQueryBuilder.withHighlightFields(highlightBuilder); NativeSearchQuery searchQuery = searchQueryBuilder.build();
AggregatedPage<Student> page = elasticsearchTemplate.queryForPage(searchQuery, Student.class, highlightResultMapper);
System.out.println(page.getTotalElements()); System.out.println(page.getTotalPages()); List<Student> students = page.getContent(); students.forEach(student -> { System.out.println(student); }); }
}
|
8.聚合查询
8.1聚合查询也是一样,springboot没有处理器需要自己创建
其实跟高亮那个处理器一样,只不过在返回值时多加了一个聚合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @Component public class AggregationResultMapper implements SearchResultMapper {
@Override public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) { long totalHits = response.getHits().getTotalHits(); List<T> list = Lists.newArrayList(); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { if(hits.getHits().length <= 0){ return null; } Map<String, Object> map = hit.getSourceAsMap(); Map<String, HighlightField> highlightFields = hit.getHighlightFields(); for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) { String key = highlightField.getKey(); HighlightField value = highlightField.getValue(); Text[] fragments = value.getFragments(); StringBuilder sb = new StringBuilder(); for (Text text : fragments) { sb.append(text); } map.put(key, sb.toString()); } T item = JSON.parseObject(JSONObject.toJSONString(map),aClass); list.add(item); } return new AggregatedPageImpl<>(list, pageable, totalHits,response.getAggregations()); }
}
|
8.2聚合查询测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @RunWith(SpringRunner.class) @SpringBootTest(classes = ESApp.class) public class EsAggregationSearchTest { @Autowired private ElasticsearchTemplate elasticsearchTemplate; @Autowired private AggregationResultMapper aggregationResultMapper; @Test public void testAggregationSearch(){ NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery()); TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("paixu").field("sage").order(Terms.Order.count(false)); searchQueryBuilder.addAggregation(termsAggregationBuilder);
NativeSearchQuery searchQuery = searchQueryBuilder.build(); AggregatedPage<Student> page = elasticsearchTemplate.queryForPage(searchQuery, Student.class, aggregationResultMapper);
StringTerms terms = (StringTerms) page.getAggregation("paixu"); List<StringTerms.Bucket> buckets = terms.getBuckets(); List<String> sages = buckets.stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList()); System.out.println(sages);
} }
|