SpringBoot进阶-集成ElasticSearch(二)

集成ES,我们使用spring-data-es模块,这块API改动挺大的,以前的方法很多都过时了,我现在使用的spring-boot版本是2.3.2

第一步,添加依赖

<!-- ElasticSearch支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

第二步,更改版本号,springboot的es模块版本号与你安装的es版本号很可能不一致,要把版本号改成你安装的版本号

<properties>
    <elasticsearch.version>7.14.0</elasticsearch.version>
</properties>

第三步,配置es地址,es可以通过9200和9300端口来通信,9200是http端口,9300是tcp端口,官方推荐用9200端口

spring.elasticsearch.rest.uris=http://localhost:9200

第四步,定义实体类,里面定义了索引名,字段名,映射关系,映射类型

@Document(indexName = "goods", type = "goods")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GoodsInfo implements Serializable {
    //id的index不能为false
    @Id
    @Field(type = FieldType.Long)
    private Long id;
    //存放时用max_word,尽量多分,搜索时用smart
    //es会把数据都保存下来,store属性没有效果
    //text类型,可分词,不可参与聚合
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String title;
    //keyword类型: 不可分词,数据会作为完整字段进行匹配,可以参与聚合
    @Field(type = FieldType.Keyword)
    private String category;
    @Field(type = FieldType.Keyword)
    private String brand;
    @Field(type = FieldType.Double)
    private Double price;
    //不需要被搜索就把index设为false
    @Field(index = false, type = FieldType.Keyword)
    private String images;
    @Field(type = FieldType.Integer)
    private Integer type;
}

第五步,定义数据操作接口

public interface GoodsInfoDao extends ElasticsearchRepository<GoodsInfo, Long> {

}

好了,整个环境搭建好了,接下去就是增删改查了,增删改很简单,直接调用dao层提供的方法,查的话虽然spring-data-es也提供了基于方法的查询,但功能太弱基本不会去用,还是要通过DSL来查询。

保存和更新

保存和更新超级简单,都是save方法,如果没有索引,索引也会自动创建

public void saveGoods() {
    GoodsInfo goodsInfo = new GoodsInfo(1L, "小米手机10 64G 幻夜黑", "手机", "小米", 4500D, "http://xxx.com/22222.jpg", 1, null);
    goodsInfoDao.save(goodsInfo);
}

 查看索引的命令

GET http://localhost:9200/goods/_mapping

删除

public void deleteGood() {
    goodsInfoDao.deleteById(1L);
}

根据id查询

public void findById() {
    Optional<GoodsInfo> optional = goodsInfoDao.findById(1L);
    if (optional.isPresent()) {
        System.out.println(optional.get());
    }
}

DSL查询

前面都没啥难度,接下去是重头戏通过DSL查询了,初看DSL会感觉有些晕,一层套一层的,这时通过熟悉的sql来辅助记忆是比较好的办法。

短语匹配(match_phrase)

select * from goods where title like '%小米%'

sql中的模糊查询对应ES的短语匹配

GET /goods/_search
{
    "query":{
        "match_phrase": {
            "title": "小米手机"
    	}
    }
}

java代码实现,我们使用ElasticsearchRestTemplate来实现DSL查询

public void testMatchPhrase() {
    QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("title", "小米手机");
    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
            //查询条件
            .withQuery(queryBuilder)
            .build();
    SearchHits<GoodsInfo> goodsInfos = elasticsearchRestTemplate.search(nativeSearchQuery, GoodsInfo.class);
    goodsInfos.getSearchHits().stream().forEach(System.out::println);
}

可以看到所有的查询条件都可以用QueryBuilders来构建,然后传给下面的NativeSearchQuery就行了。

匹配查询(match)

match查询类似于分词再like,比如小米手机粉会被分词成小米,手机,粉,sql查询语句类似于

select * from goods where title like '%小米%' or title like '%手机%' or title like '%粉%'

 DSL语句:

GET /goods/_search
{
  "query": {
    "match": {
      "title": "小米手机粉"
    }
  }
}

JAVA代码(NativeSearchQuery跟上面一样): 

QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米手机粉");

如果要实现select * from goods where title like '%小米%' and title like '%手机%' and title like '%粉%'这种and类型的呢?很简单,加个operator

GET /goods/_search
{
  "query": {
    "match": {
      "title": {
        "query": "小米手机",
        "operator": "and"
      }
    }
  }
}
QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米手机").operator(Operator.AND);

 多条件匹配(multi match)

一件商品不仅有标题,还有商品描述,如果想在标题或者商品描述中查询相关关键字,就需要用到multi match

{
  "query": {
    "multi_match": {
        "query" : "拍照高性能",
        "fields" : ["title", "description"],
        "operator": "and"
    }
  }
}

 代码实现

QueryBuilder queryBuilder = QueryBuilders
        .multiMatchQuery("拍照高性能", "title", "description")
        .operator(Operator.AND);

词条查询(term)

精确比配实现方式, select * from goods where brand = '小米'

GET /goods/_search
{
    "query":{
        "term":{
            "brand": "小米"
        }
    }
}
QueryBuilder queryBuilder = QueryBuilders.termQuery("brand", "小米");

范围查询(range)

 select * from goods where price >= 5000 and price < 6000

GET /goods/_search
{
    "query":{
        "range": {
            "price": {
                "gte":  5000,
                "lt":   6000
            }
    	}
    }
}
QueryBuilder queryBuilder = QueryBuilders.rangeQuery("price").gte(5000).lt(6000);

 bool组合

多个条件同时满足需要用到组合查询

GET /goods/_search
{
    "query":{
        "bool":{
        	"must": [
        	  {
        	    "term": {
        	      "brand": "华为"
        	    }
        	  }
        	],
        	"must_not": [
      	   {
        	    "term": {
        	      "price": 3500
        	    }
        	  }
        	],
        	"should": [
        	  {
        	    "match": {
        	      "title": "极光紫"
        	    }
        	  }
        	]
        }
    }
}
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("brand", "华为"))
                .mustNot(QueryBuilders.termQuery("price", 3500))
                .should(QueryBuilders.matchQuery("title", "极光紫"));

分页排序高亮

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("title", "小米手机").operator(Operator.AND));
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
        //查询条件
        .withQuery(boolQueryBuilder)
        //分页,page从0开始
        .withPageable(PageRequest.of(0, 10))
        //排序
        .withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC))
        //高亮字段显示
        .withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"))
        .build();
SearchHits<GoodsInfo> goodsInfos = elasticsearchRestTemplate.search(nativeSearchQuery, GoodsInfo.class);
goodsInfos.forEach(item -> System.out.println(item.toString()));

看不明白也没关系,还有贴心的项目代码参考

参考项目(模块: SpringBoot-HelloWorld): https://gitee.com/huatin/java-test  

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值