SpringBoot集成Elasticsearch

目录

  • 一、环境
  • 二、集成步骤
    • 2.1、引入依赖
    • 2.2、配置
    • 2.3、实体类
    • 2.3、基本操作
      • 2.3.1、批量导入
      • 2.3.2、分页搜索并高亮
      • 2.3.3、常用DSL
  • 三、项目分享

一、环境

  • SpringBoot 2.3.0.RELEASE
  • Elasticsearch 7.13.4

二、集成步骤

2.1、引入依赖

SpringBoot中集成Elasticsearch,要注意一些依赖的版本和Elasticsearch服务器版本一致。

<properties>
	<elasticsearch.version>7.13.4elasticsearch.version>
properties>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-elasticsearchartifactId>
    <exclusions>
        <exclusion>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-high-level-clientartifactId>
        exclusion>
        <exclusion>
            <groupId>org.elasticsearch.clientgroupId>
            <artifactId>elasticsearch-rest-clientartifactId>
        exclusion>
        <exclusion>
            <groupId>org.elasticsearchgroupId>
            <artifactId>elasticsearchartifactId>
        exclusion>
    exclusions>
dependency>


<dependency>
    <groupId>org.elasticsearch.clientgroupId>
    <artifactId>elasticsearch-rest-high-level-clientartifactId>
    <version>${elasticsearch.version}version>
dependency>
<dependency>
    <groupId>org.elasticsearch.clientgroupId>
    <artifactId>elasticsearch-rest-clientartifactId>
    <version>${elasticsearch.version}version>
dependency>
<dependency>
    <groupId>org.elasticsearchgroupId>
    <artifactId>elasticsearchartifactId>
    <version>${elasticsearch.version}version>
dependency>

2.2、配置

application配置文件:

#elasticsearch
spring.elasticsearch.rest.uris=124.223.44.254:9200
spring.elasticsearch.rest.username=elasticUser
spring.elasticsearch.rest.password='Password123.'

2.3、实体类

程序启动会默认据此实体类自动创建对应索引,

@Data
@Document(indexName = PrescriptionPo.indexName)
public class PrescriptionPo implements Serializable {

    private static final long serialVersionUID = 4138692353689910309L;
    public static final String indexName = "prescription";

    @Id
    @JSONField(ordinal = 1)
    private String id;

    @Field(type = FieldType.Keyword)
    @JSONField(ordinal = 2)
    private String code;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    @JSONField(ordinal = 3)
    private String detailContent;

    @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @JSONField(ordinal = 4)
    private Date publishTime;

    @Field(type = FieldType.Keyword)
    @JSONField(ordinal = 5)
    private String authorId;

    @Field(index = true, type = FieldType.Text, analyzer = "ik_smart", store = false, searchAnalyzer = "ik_smart")
    @JSONField(ordinal = 6)
    private String authorName;

    @JSONField(ordinal = 7)
    private List<String> picUrls;

    @Field(type = FieldType.Keyword)
    @JSONField(ordinal = 8)
    private String requestUrl;

    @Field(type = FieldType.Long)
    @JSONField(ordinal = 9)
    private Long batchId;
}

若因某些ES服务版本导致不能生成正确的索引映射,也可通过DSL提前手动创建索引,

PUT prescription
{
  "mappings" : {
    "properties" : {
      "authorId" : {
        "type" : "keyword"
      },
      "authorName" : {
        "type" : "text",
        "analyzer" : "ik_smart"
      },
      "batchId" : {
        "type" : "long"
      },
      "code" : {
        "type" : "keyword"
      },
      "detailContent" : {
        "type" : "text",
        "analyzer" : "ik_max_word"
      },
      "id" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "picUrls" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "publishTime" : {
        "type" : "date",
        "format" : "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      },
      "requestUrl" : {
        "type" : "keyword"
      }
    }
  }
}

2.3、基本操作

SpringBoot里操作Elasticsearch有很多种方式,可以使用SpringData的ElasticsearchRepository实现简单的操作,可以使用SpringData的ElasticsearchRestTemplate实现更复杂的操作如搜索高亮和批量导入等操作,也可以自己封装一个通过操作DSL的Restful客户端,更加自由。

2.3.1、批量导入

public void sync(List<PrescriptionPo> prescriptionPoList) {
    List<IndexQuery> queries = new ArrayList<>();
    IndexCoordinates indexCoordinates = IndexCoordinates.of(PrescriptionPo.indexName);
    int count = 0;
    for (PrescriptionPo po : prescriptionPoList) {
        IndexQuery query = new IndexQuery();
        query.setId(po.getId());
        query.setSource(JSON.toJSONString(po));
        queries.add(query);
        // 每批次1000条提交索引
        if (count != 0 && count % 1000 == 0) {
            elasticsearchRestTemplate.bulkIndex(queries, indexCoordinates);
            queries.clear();
        }
        count++;
    }
    // 不足一批次的最后提交
    if (queries.size() > 0) {
        elasticsearchRestTemplate.bulkIndex(queries, indexCoordinates);
    }
    elasticsearchRestTemplate.indexOps(indexCoordinates).refresh();
    log.info("Finished bulk {}!", prescriptionList.size());
}

2.3.2、分页搜索并高亮

使用ElasticsearchRestTemplate配合SearchHits实现分页搜索并高亮显示,

@Override
public Page<PrescriptionDto> searchPrescription(String keyword, Integer pageNum, Integer pageSize) {
    Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
    NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field(new HighlightBuilder.Field("detailContent"));
    highlightBuilder.preTags("").postTags("");
    searchQueryBuilder.withPageable(pageable)
            .withQuery(QueryBuilders.matchQuery("detailContent", keyword))
            .withHighlightBuilder(highlightBuilder);
    SearchHits<PrescriptionPo> searchHits = elasticsearchRestTemplate.search(searchQueryBuilder.build(), PrescriptionPo.class);
    // 创建list对象
    List<PrescriptionDto> prescriptionDtoList = new ArrayList<>();
    searchHits.forEach(item -> {
        PrescriptionPo prescriptionPo = item.getContent();
        prescriptionDtoList.add(prescriptionPo.makeDto(item));
    });
    // 组装分页对象
    Page<PrescriptionDto> page = new PageImpl<>(prescriptionDtoList, pageable, searchHits.getTotalHits());
    return page;
}

使用ElasticsearchRepository则不能同时实现分页搜索和高亮,

public interface PrescriptionRepository extends ElasticsearchRepository<PrescriptionPo, String> {

    // 用DSL,对detailContent分词后搜索
    @Query("{\"match\": {\"detailContent\": \"?0\"}}")
    @Highlight(
            fields = {@HighlightField(name = "detailContent")},
            parameters = @HighlightParameters(preTags = {""}, postTags = {""}, numberOfFragments = 0)
    )
    List<SearchHit<PrescriptionPo>> matchByContentWithDsl(String detailContent, Pageable pageable);

    // 支持分页,不支持高亮
    @Query("{\"match\": {\"detailContent\": \"?0\"}}")
    Page<PrescriptionPo> matchByContentWithDsl2(String detailContent, Pageable pageable);

    Optional<PrescriptionPo> findByCode(String code);
}

2.3.3、常用DSL

GET _cat/indices?v
GET _cat/plugins
GET _search
{
  "query": {
    "match_all": {}
  }
}
GET /_analyze
{
  "text":"中华人民共和国国徽",
  "analyzer":"ik_smart"
}

DELETE prescription
GET prescription/_mappings
GET prescription/_count
GET prescription/_search?pretty&from=0&size=2
GET prescription/_search?pretty&from=0&size=2
{
  "query": {
    "match": {
      "detailContent": "咳嗽"
    }
  },
  "highlight" : {
      "pre_tags" : [""],
      "post_tags" : [""],
      "fields" : {
          "detailContent" : {}
      }
  }
}
GET prescription/_search?pretty
{
  "query": {
    "wildcard": {
      "code": "*LaONPnzhG"
    }
  },
  "sort": [
    {
      "publishTime": {
        "order": "desc"
      }
    }
  ]
}
GET prescription/_search?pretty&from=0
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "code": "Lbzt9cKrB"
          }
        }
      ]
    }
  }
}
GET prescription/_search?q=*&sort=publishTime:desc&pretty
# 指定字段更新
POST prescription/_update/1642665269755_RTX4FX
{
  "doc": {
      "detailContent": "xx"
  }
}
# 全字段更新
POST prescription/_doc/9gUwDn0BA5KB_D7SWQLN
{
  "detailContent": "xxx"
}
# 分组统计每批各自总数
GET prescription/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_batchId": {
      "terms": {
        "field": "batchId"
      }
    }
  }
}
# 并计算每批的平均发布时间,因为请求setsize=0,所以响应仅包含聚合结果
GET prescription/_search?pretty
{
  "size": 0,
  "aggs": {
    "group_by_batchId": {
      "terms": {
        "field": "batchId"
      },
      "aggs": {
        "average_publishTime": {
          "avg": {
            "field": "publishTime"
          }
        }
      }
    }
  }
}
# 备份到新索引
POST _reindex
{
  "source": {
    "index": "prescription"
  },
  "dest": {
    "index": "prescription_copy20220110"
  }
}

三、项目分享

分享一个搜索头疼脑热和中药信息的网址,
https://124.223.54.92/ 或 http://124.223.54.92/,


Ps,其中所有信息仅供娱乐!
Ps,其中所有信息仅供娱乐!
Ps,其中所有信息仅供娱乐!

因使用了自己生成的ssl证书,可能谷歌浏览器打不开网址,提示您的连接不是私密连接
SpringBoot集成Elasticsearch_第1张图片
在浏览器页面键入thisisunsafe即可。

你可能感兴趣的:(SpringBoot,ELK,elasticsearch,spring,boot)