• Springboot基于ElasticSearch全文搜索引擎策略实现


    一、ElasticSearch概念简介

    ElasticSearch是一个基于Lucene的开源搜索引擎,具有分布式、多租户能力的全文搜索引擎。ElasticSearch的设计目标是实现分布式、可扩展和速度快的搜索架构,使得用户在数据量较大的情况下依然能够快速高效地对数据进行搜索和分析。

    ElasticSearch使用RESTful API进行操作,支持结构化、非结构化数据的索引和搜索,适合用来解决大量数据的全文搜索、数据分析、日志查询等问题。

    二、ElasticSearch基本理论

    • 文档(Document):Documents是ElasticSearch中的最小数据单元类似我们关系数据库的一条记录,一个文档由JSON格式数据构成。Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。Document 使用 JSON 格式表示,下面是一个例子。

    1. {
    2. "user": "张三",
    3. "title": "工程师",
    4. "desc": "数据库管理"
    5. }
    • 索引(Index):Indexes类似于关系数据库中的数据库,每个索引包含多个类型和文档。ElasticSearch通过索引词典提高搜索效率。Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。

    1. --下面的命令可以查看当前节点的所有 Index。
    2. curl -X GET 'http://localhost:9200/_cat/indices?v'
    • 分片(Shard)与副本(Replica):Index可以分为多个Shards,并且每个Shard可以有多个Replicas。分片提高了并行搜索和存储的能力,而副本提供了高可用性。

    • 倒排索引:ElasticSearch使用倒排索引数据结构来实现快速的全文搜索。倒排索引将一个单词映射到包含这个单词的文档,从而加速搜索查询。

    三、ElasticSearch应用场景

    1. 全文搜索:ElasticSearch可以用于网站、文档系统中的全文搜索功能。

    2. 日志分析:与Logstash和Kibana组合成ELK Stack,可以构建日志收集和分析系统。

    3. 大数据分析:利用其强大的聚合功能和分布式计算能力进行实时数据分析。

    4. 推荐系统:通过搜索引擎相关性计算和评分功能,实现个性化推荐系统。

    四、ElasticSearch在Linux环境下的安装部署

    Elastic 需要 Java 8 环境。如果你的机器还没安装 Java,以下是在Linux系统(以Ubuntu为例)中安装ElasticSearch的步骤:

    1.安装Java环境 ElasticSearch要求安装Java 8或以上版本。

    1. sudo apt update
    2. sudo apt install openjdk-11-jdk

    2.下载并安装ElasticSearch

    1. wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.0-amd64.deb
    2. sudo dpkg -i elasticsearch-7.10.0-amd64.deb

    3.启动并设置ElasticSearch为开机自启动

    1. sudo systemctl start elasticsearch
    2. sudo systemctl enable elasticsearch

    4.验证安装

    curl -X GET "localhost:9200/"

    会返回以下信息

    1. {
    2. "name" : "atntrTf",
    3. "cluster_name" : "elasticsearch",
    4. "cluster_uuid" : "tf9250XhQ6ee4h7YI11anA",
    5. "version" : {
    6. "number" : "7.10.0",
    7. "build_hash" : "19c13d0",
    8. "build_date" : "2022-07-18T20:44:24.823Z",
    9. "build_snapshot" : false,
    10. "lucene_version" : "6.6.0"
    11. },
    12. "tagline" : "You Know, for Search"
    13. }

    5.中文词搜索设置

    首先,安装中文分词插件。这里使用的是 ik,也可以考虑其他插件(比如 smartcn)。

    插件的下载地址:GitHub - infinilabs/analysis-ik: 🚌 The IK Analysis plugin integrates Lucene IK analyzer into Elasticsearch and OpenSearch, support customized dictionary.

    ./bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.4.1

    上面代码安装的是8.4.1版的插件,与 Elastic 7.x及以上的版本 配合使用,具体细节查看插件的版本库文档教程。

    接着,重新启动 Elastic,就会自动加载这个新安装的插件。

    然后,新建一个 Index,指定需要分词的字段。这一步根据数据结构而异,下面的命令只针对本文。基本上,凡是需要搜索的中文字段,都要单独设置一下。

    1. curl -X PUT 'localhost:9200/accounts' -d '
    2. {
    3. "mappings": {
    4. "person": {
    5. "properties": {
    6. "user": {
    7. "type": "text",
    8. "analyzer": "ik_max_word",
    9. "search_analyzer": "ik_max_word"
    10. },
    11. "title": {
    12. "type": "text",
    13. "analyzer": "ik_max_word",
    14. "search_analyzer": "ik_max_word"
    15. },
    16. "desc": {
    17. "type": "text",
    18. "analyzer": "ik_max_word",
    19. "search_analyzer": "ik_max_word"
    20. }
    21. }
    22. }
    23. }
    24. }'

    上面代码中,首先新建一个名称为accounts的 Index,里面有一个名称为person的 Type。person有三个字段。

    这三个字段都是中文,而且类型都是文本(text),所以需要指定中文分词器,不能使用默认的英文分词器。Elastic 的分词器称为 analyzer。我们对每个字段指定分词器。

    上面代码中,analyzer是字段文本的分词器,search_analyzer是搜索词的分词器。ik_max_word分词器是插件ik提供的,可以对文本进行最大数量的分词。

    五、ElasticSearch与Spring Boot 2的整合

    1、核心依赖

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-data-elasticsearchartifactId>
    4. <version>${spring-boot.version}version>
    5. dependency>

    2、yml配置文件

    1. spring:
    2. application:
    3. name: ware-elastic-search
    4. data:
    5. elasticsearch:
    6. # 默认 elasticsearch
    7. cluster-name: elasticsearch
    8. # 9200作为Http协议,主要用于外部通讯
    9. # 9300作为Tcp协议,jar之间就是通过tcp协议通讯
    10. cluster-nodes: 10.98.3.22:9300

    3、实体类配置

    Document配置,加上了@Document注解之后,默认情况下这个实体中所有的属性都会被建立索引、并且分词。

    1. indexName索引名称 理解为数据库名 限定小写
    2. type 理解为数据库的表名称
    3. shards = 5 默认分区数
    4. replicas = 1 每个分区默认的备份数
    5. refreshInterval = "1s" 刷新间隔
    6. indexStoreType = "fs" 索引文件存储类型

    Java代码

    1. import org.springframework.data.annotation.Id;
    2. import org.springframework.data.elasticsearch.annotations.Document;
    3. @Document(indexName = "systemlogindex",type = "systemlog")
    4. public class SystemLog {
    5. //Id注解Elasticsearch里相应于该列就是主键,查询时可以使用主键查询
    6. @Id
    7. private Long id;
    8. private String orderNo;
    9. private String userId;
    10. private String userName;
    11. private String logData;
    12. private String createTime;
    13. }

    实现ElasticsearchRepository接口。

    1. public interface SystemLogRepository
    2. extends ElasticsearchRepository {
    3. }

    4.演示实例实现

    1. @Service
    2. public class SystemLogServiceImpl implements SystemLogService {
    3. @Resource
    4. private SystemLogRepository systemLogRepository ;
    5. @Override
    6. public String esInsert(Integer num) {
    7. for (int i = 0 ; i < num ; i++){
    8. SystemLog systemLog= new SystemLog() ;
    9. systemLog.setId(System.currentTimeMillis());
    10. systemLog.setOrderNo(DateUtil.formatDate(new Date(),DateUtil.DATE_FORMAT_02)+System.currentTimeMillis());
    11. systemLog.setUserId("userId"+i);
    12. systemLog.setUserName("张三"+i);
    13. systemLog.setCreateTime(DateUtil.formatDate(new Date(),DateUtil.DATE_FORMAT_01));
    14. systemLog.setLogData("用户做了插入数据操作。")
    15. systemLogRepository.save(requestLog) ;
    16. }
    17. return "success" ;
    18. }
    19. @Override
    20. public Iterable esFindAll (){
    21. return systemLogRepository.findAll() ;
    22. }
    23. @Override
    24. public String esUpdateById(SystemLog systemLog) {
    25. systemLogRepository.save(systemLog);
    26. return "success" ;
    27. }
    28. @Override
    29. public Optional esSelectById(Long id) {
    30. return systemLogRepository.findById(id) ;
    31. }
    32. @Override
    33. public Iterable esFindOrder() {
    34. // 用户名倒序
    35. // Sort sort = new Sort(Sort.Direction.DESC,"userName.keyword") ;
    36. // 创建时间正序
    37. Sort sort = new Sort(Sort.Direction.ASC,"createTime.keyword") ;
    38. return systemLogRepository.findAll(sort) ;
    39. }
    40. @Override
    41. public Iterable esFindOrders() {
    42. List sortList = new ArrayList<>() ;
    43. Sort.Order sort1 = new Sort.Order(Sort.Direction.ASC,"createTime.keyword") ;
    44. Sort.Order sort2 = new Sort.Order(Sort.Direction.DESC,"userName.keyword") ;
    45. sortList.add(sort1) ;
    46. sortList.add(sort2) ;
    47. Sort orders = Sort.by(sortList) ;
    48. return systemLogRepository.findAll(orders) ;
    49. }
    50. @Override
    51. public Iterable search() {
    52. // 全文搜索关键字
    53. /*
    54. String queryString="张三";
    55. QueryStringQueryBuilder builder = new QueryStringQueryBuilder(queryString);
    56. systemLogRepository.search(builder) ;
    57. */
    58. /*
    59. * 多条件查询
    60. */
    61. QueryBuilder builder = QueryBuilders.boolQuery()
    62. // .must(QueryBuilders.matchQuery("userName.keyword", "历张")) 搜索不到
    63. .must(QueryBuilders.matchQuery("userName", "张三")) // 可以搜索
    64. .must(QueryBuilders.matchQuery("orderNo", "20190613736278243"));
    65. return systemLogRepository.search(builder) ;
    66. }
    67. }

    总结

    ElasticSearch作为强大的分布式全文搜索引擎具备许多强大的功能,通过在Spring Boot 2项目中的简单集成,可以很容易地利用ElasticSearch的搜索和查询能力,满足现代Web应用中的搜索需求。

  • 相关阅读:
    【微服务】软件架构的演变之路
    vue2 + antd1.7.8 和 vue3 + antd2.2.8表单动态添加删除表单项
    杰哥教你面试之一百问系列:java中高级多线程concurrent的使用
    CSS让两个标签在同一行显示并自适应宽度
    Grafana安装配置
    互联网Java工程师面试题·Elasticsearch 篇·第一弹
    数据库性能翻3倍:Redis on Flash分层存储技术是如何做到的?
    网络安全笔记 -- 文件上传2(内容逻辑数组绕过、中间件漏洞绕过、WAF绕过)
    Spring MVC 请求处理过程。你这样回答保证通过面试!
    处理element ui 表格中 按钮 loading问题
  • 原文地址:https://blog.csdn.net/LQzhang_11/article/details/139827479