【Spring Boot】Spring Boot之使用 Spring Data Elasticsearch 整合elasticsearch


一、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);
        }
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM