集成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