一、Spring Data Elasticsearch簡單介紹
Spring Data Elasticsearch項目將核心Spring概念應用於使用Elasticsearch搜索引擎開發解決方案。我們提供了一個“模板”作為存儲、查詢、排序和划分文檔的高級抽象。您將注意到Spring Framewor與Spring data solr和mongodb支持的相似之處
GitHub地址:https://github.com/zhangboqing/spring-boot-demo-elasticsearch
使用的spring boot版本:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
二、整合步驟
1)maven依賴
<!-- Elasticsearch --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
2)application.yml
spring: elasticsearch: rest: uris: - http://localhost:9200 username: elastic password: 123456
3)定義實體,一個實體對於一個index
/** * @author zhangboqing * @date 2019-12-06 */ public interface EsConsts { /** * 所以index都使用該類型名稱 */ String DEFAULT_TYPE_NAME = "_doc"; /** * 索引名稱 */ String INDEX_NAME_MERCURY = "goods"; }
/** * @author zhangboqing * @date 2019-12-06 */ @Document(indexName = EsConsts.INDEX_NAME_MERCURY, type = EsConsts.DEFAULT_TYPE_NAME, shards = 1, replicas = 0) @Data @AllArgsConstructor @NoArgsConstructor public class GoodsESEntity { // 篩選條件包括:商品名稱,品牌,規格,適用車型,商品編號,原廠編號 /** * 主鍵,商品ID */ @Id private Long goodsId; /** * 商品名稱 */ @Field(type = FieldType.Keyword) private String goodsName; /** * 品牌 */ @Field(type = FieldType.Keyword) private String goodBrand; /** * 規格 */ @Field(type = FieldType.Keyword) private String goodsSpec; /** * 商品編號 */ @Field(type = FieldType.Keyword) private String goodsAccessoriesCode; /** * 原廠編號 */ @Field(type = FieldType.Keyword) private String goodsOriginalFactoryCode; /** * 復合字段,會被分詞后存儲 */ @Field(type = FieldType.Text, analyzer = "ik_smart") private String groupData; }
4)定義Repository
/** * @author zhangboqing * @date 2019-12-06 */ public interface GoodsESRepository extends ElasticsearchRepository<GoodsESEntity, Long> { /** * 根據goodsId區間查詢 */ List<GoodsESEntity> findByGoodsIdBetween(Integer min, Integer max); }
三、測試
/** * @Author zhangboqing * @Date 2020-01-03 */ @SpringBootTest @Slf4j public class GoodsESRepositoryTest { @Autowired private GoodsESRepository goodsESRepository; /** * 測試新增 */ @Test public void save() { GoodsESEntity goodsESEntity1 = new GoodsESEntity(2L, "尾燈 L 大眾速騰", "國際品牌", "16D 945 095", "31231231", "16D 945 095", "尾燈 L 大眾速騰 國際品牌 16D 945 095 31231231 16D 945 095"); GoodsESEntity goodsESEntity2 = new GoodsESEntity(1L, "后", "國際品牌", "16D 945 095", "31231231", "16D 945 095", "后 國際品牌 16D 945 095 31231231 16D 945 095"); Iterable<GoodsESEntity> goodsESEntities = goodsESRepository.saveAll(Arrays.asList(goodsESEntity1, goodsESEntity2)); log.info("【save】= {}", goodsESEntities); } /** * 測試更新 */ @Test public void update() { goodsESRepository.findById(1L).ifPresent(goodsESEntity -> { goodsESEntity.setGoodsName(goodsESEntity.getGoodsName() + "\n更新更新更新更新更新"); GoodsESEntity save = goodsESRepository.save(goodsESEntity); log.info("【save】= {}", save); }); } /** * 測試刪除 */ @Test public void delete() { // 主鍵刪除 goodsESRepository.deleteById(1L); // 對象刪除 goodsESRepository.findById(2L).ifPresent(goodsESEntity -> goodsESRepository.delete(goodsESEntity)); // 批量刪除 goodsESRepository.deleteAll(goodsESRepository.findAll()); } /** * 測試普通查詢,按goodsId倒序 */ @Test public void select() { goodsESRepository.findAll(Sort.by(Sort.Direction.DESC, "goodsId")) .forEach(goodsESEntity -> log.info("【goods】: {}", JSON.toJSONString(goodsESEntity))); } /** * 自定義查詢,根據goodsId范圍查詢 */ @Test public void customSelectRangeOfAge() { goodsESRepository.findByGoodsIdBetween(1, 2).forEach(goodsESEntity -> log.info("【goods】: {}", JSON.toJSONString(goodsESEntity))); } /** * 高級查詢 */ @Test public void advanceSelect() { // QueryBuilders 提供了很多靜態方法,可以實現大部分查詢條件的封裝 MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("goodsName", "保時捷跑車V20"); log.info("【queryBuilder】= {}", queryBuilder.toString()); goodsESRepository.search(queryBuilder).forEach(goodsESEntity -> log.info("【goods】: {}", JSON.toJSONString(goodsESEntity))); } /** * 自定義高級查詢 */ @Test public void customAdvanceSelect() { // 構造查詢條件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分詞條件 queryBuilder.withQuery(QueryBuilders.matchQuery("goodsName", "保時捷跑車V20")); // 排序條件 queryBuilder.withSort(SortBuilders.fieldSort("goodsId").order(SortOrder.DESC)); // 分頁條件 queryBuilder.withPageable(PageRequest.of(0, 2)); Page<GoodsESEntity> goodsESEntities = goodsESRepository.search(queryBuilder.build()); log.info("【people】總條數 = {}", goodsESEntities.getTotalElements()); log.info("【people】總頁數 = {}", goodsESEntities.getTotalPages()); goodsESEntities.forEach(goodsESEntity -> log.info("【goods】= {}",JSON.toJSONString(goodsESEntity))); } /** * 測試聚合,測試平均goodsId */ @Test public void avg() { // 構造查詢條件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 不查詢任何結果 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null)); // 平均goodsId queryBuilder.addAggregation(AggregationBuilders.avg("goodsIdAvg").field("goodsId")); log.info("【queryBuilder】= {}", JSON.toJSONString(queryBuilder.build())); AggregatedPage<GoodsESEntity> goodsESEntities = (AggregatedPage<GoodsESEntity>) goodsESRepository.search(queryBuilder.build()); double avgGoodsId = ((InternalAvg) goodsESEntities.getAggregation("goodsIdAvg")).getValue(); log.info("【avgGoodsId】= {}", avgGoodsId); } /** * 測試高級聚合查詢 */ @Test public void advanceAgg() { // 構造查詢條件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 不查詢任何結果 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null)); // 1. 添加一個新的聚合,聚合類型為terms,聚合名稱為goodsName,聚合字段為goodsId queryBuilder.addAggregation(AggregationBuilders.terms("goodsName").field("goodsName") // 2. 在goodsName聚合桶內進行嵌套聚合,求平均goodsId .subAggregation(AggregationBuilders.avg("goodsIdAvg").field("goodsId"))); log.info("【queryBuilder】= {}", JSON.toJSONString(queryBuilder.build())); // 3. 查詢 AggregatedPage<GoodsESEntity> people = (AggregatedPage<GoodsESEntity>) goodsESRepository.search(queryBuilder.build()); // 4. 解析 // 4.1. 從結果中取出名為 goodsName 的那個聚合,因為是利用String類型字段來進行的term聚合,所以結果要強轉為StringTerm類型 StringTerms goodsName = (StringTerms) people.getAggregation("goodsName"); // 4.2. 獲取桶 List<StringTerms.Bucket> buckets = goodsName.getBuckets(); for (StringTerms.Bucket bucket : buckets) { // 4.3. 獲取桶中的key,即goodsName名稱 4.4. 獲取桶中的文檔數量 log.info("{} 總共有 {} 個", bucket.getKeyAsString(), bucket.getDocCount()); // 4.5. 獲取子聚合結果: InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("goodsIdAvg"); log.info("平均goodsId:{}", avg); } } }