初识搜索引擎 —— ElasticSearch

ElasticSearch

概述

Lucene

Lucene 是 Apache 下的一个项目,是一个开源的全文检索引擎工具包。

Lucene 是一个全文检索引擎的架构,提供完整的查询引擎索引引擎

Libana

Kibana 是一种数据可视化和挖掘工具,可以用于日志和时间序列分析、应用程序监控和运营智能使用案例。

Kibana 提供了强大且易用的功能,例如直方图、线形图、饼图、热图和内置的地理空间支持。

ElasticSearch 简称 es,是一个开源的高扩展到分布式全文检索引擎

ELK

ELK:ElasticSearch、Logstash、Kibana

  • ElasticSearch:基于 Lucene 的分布式搜索框架

  • Logstash:中央数据流引擎,从不同地方收集不同的格式数据过滤输出到不同的目的地

  • Kibana:数据展示框架

数据的收集及清洗 -> 数据分析,存储(ES) -> 数据展示(Kibana)

ES 核心

ElasticSearch 是面向文档的

  • 索引
    • 映射类型的容器
  • 类型(7版本淘汰,8版本弃用)mapping
    • 不加上类型也可以自动匹配
  • 文档 documents
    • 索引和搜索数据的最小单位是文档
  • 分片
    • 在本质上,一个分片就是一个 Lucene 索引,也是一个包含倒排索引的文件目录

安装

安装 ES

  1. 官网上下载对应系统下你想选择使用的版本的压缩包
  2. 解压缩
  3. 打开 bat 脚本文件(默认端口号9200)

可视化界面安装 – ES head

  1. 从 GitHub 下载
  2. 跨域设置(elasticsearch.yaml)
  3. 访问可视化页面(默认端口号9100)

注意:ES 要求索引名都必须是小写,在 head 中使用大写无法成功但无提示!!

安装 Kibana

注意:与 RabbitMQ 一直,Kibana 版本需要与 ES 版本一致

  1. 从官网下载与 ES 版本一致的压缩包
  2. 解压使用
  3. 打开 bat 脚本文件(默认端口号5601)

另:

需要汉化的可以在 config 文件夹下修改 kibana.yml 文件中的配置

在这里插入图片描述

IK 分词器(插件)

概要

将一段语句划分成多个关键词,在检索时将数据库或索引中的数据进行分词并匹配的插件。(中文)

IK 分词器的两种分词算法:

  • ik_smart:最少划分
  • ik_max_word:最细粒度划分

安装

  1. 从 GitHub 下载 zip 文件(注意:此处下载下来不应该是源码,使用我提供的链接寻找需要的版本下载即可源码

  2. 解压缩放入 ES 中的 plugins 文件夹中的 ik 文件夹

  3. 使用 elasticsearch-plugin list 命令查看 loaded 的插件(bin目录下)

配置自己的分词可以在 config 文件夹中增加自己的 .dic 文件并配置 IKAnalyzer.cfg.xml

基本操作

Rest 风格

methodurlcomment
PUTxxxx:port/index/type/document_idcreate document(指定id)
POSTxxxx:port/index/typecreate document(随机id)
POSTxxxx:port/index/type/document_id/_updateupdate document
DELETExxxx:port/index/type/document_iddelete document
GETxxxx:port/index/type/document_idget document by id
POSTxxxx:port/index/type/document_id/_searchsearch data

索引操作

索引操作和文档操作的命令在 Kibana 中的 Dev Tools 中进行

  1. 创建索引

    # PUT /索引名/[:类型名]/文档id
    PUT /test-01/type-01/01
    # 请求体
    {
      "name": "xiaoming",
      "age": "3"
    }
    
  2. 创建索引规则(mapping 映射)

    PUT /test-02
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "long"
          },
          "birthday": {
            "type": "date"
          }
        }
      }
    }
    
  3. 创建索引及 document(不指定 type,默认_doc)

    PUT /test-03/_doc/01
    {
      "name": "xiaoming",
      "age": 3,
      "birthday": "xxxx-xx-xx"
    }
    
  4. 查看某个索引具体信息

    GET test-02
    
  5. 查看 ES 索引情况

    GET _cat/
    
  6. 修改 document

    • 直接覆盖,使用原 REST 语句(_version 会更新)(PUT)

      PUT /test-03/_doc/01
      {
      	"name": "xiaoyang",
      	"age": 3,
      	"birthday": "xxxx-xx-xx"
      }
      
    • 使用修改 document 的 REST(POST)

      # POST /{index}/_update/{id}
      POST /test-03/_update/01
      {
      	"name": "Test-user",
      	"age": 3,
      	"birthday": "xxxx-xx-xx"
      }
      
  7. 删除索引

    # DELETE {index}/{id}
    DELETE test-01
    

文档操作

  1. 创建文档

    # PUT /index/[:type]/id
    PUT /test-study/_doc/01
    
  2. 查询文档

    # GET /index/[:type]/id
    GET /test-study/01
    
  3. 更新文档

    • 直接覆盖,使用原 REST 语句(_version 会更新)(PUT)

      PUT /test-03/_doc/01
      {
      	"name": "xiaoyang",
      	"age": 3,
      	"birthday": "xxxx-xx-xx"
      }
      
    • 使用修改 document 的 REST(POST)

      # POST /{index}/_update/{id}
      POST /test-03/_update/01
      {
      	"name": "Test-user",
      	"age": 3,
      	"birthday": "xxxx-xx-xx"
      }
      #
      POST /test-03/_update/01
      {
      	"doc": {
      		"name": "Test-user"
      	}
      }
      
  4. 查询操作(条件查询)

    text:数据类型,会通过分词器进行分词

    keyword:数据类型,不会进行分词

    match:模糊查询

    term:精确匹配查询

    • 简单条件查询

      # GET /index/_search?q=查询条件(key:value)
      GET /test-03/_search?q=name:Test-user
      
    • 复杂条件查询

      GET /index/_search
      {
      	"query":{
      		"match": {
      			"key": "value"
      		}
      	},
      	# 结果过滤,类比数据库查询中 指定返回字段的语句
      	"_source": ["key-01", "key-02"]# 排序,
      	"sort": [
      		{
      			"age": {
      				# desc: 降序 asc:升序
      				"order": "asc"
      			}
      		}
      	],
      	# 分页查询 from:从第几页开始,size:返回多少个文档
      	"from": 0,
      	"size": 1,
      }
      

      布尔查询

      # and 查询
      GET /index/_search
      {
      	"query":{
          	"bool": {
      			"must": [
                      "match": {
                          "key": "value"	
                      },
                      "match": {
                          "key": "value"
                      }
                  ]
      		}
      	}
      }
      
      # or 查询
      GET /index/_search
      {
      	"query":{
      		"bool": {
      			"should": [
                      "match": {
                          "key": "value"	
                      },
                      "match": {
                          "key": "value"
                      }
                  ]
      		}
      	}
      }
      # not 查询
      should -> must_not
      
      # filter 过滤查询
      "filter": [
          {
              "range": {
                  "age": {
                      "gt": 33
                      }
              }
          }
      ]
      
      # 匹配查询 match会使用分词器进行查询(对文档进行分析分词后,再进行查询)
      "match":{
      	"tags": "xx xx"
      }
      
      # 精确查询 term 倒排索引
      "query": {
      	"term": {
      		"key": "value"
      	}
      }
      
      # 高亮查询
      GET /index/type/_search
      {
        "query": {
          "match": {
            "name": "xxx"
          }
        },
        # 
        "highlight": {
          "fields": {
            "name": {}
          } 
        }
        # 自定义高亮
        "highlight": {
          "pre_tags": "<p class='key' style='color:red'>", 
          "post_tags": "</p>", 
          "fields": {
            "name": {}
          } 
        }
      }
      

SpringBoot集成

需要

  • 准备 ElasticSearch
  • 准备 idea

使用 SpringBoot 集成 ES 时,根据官方文档进行连接及相关操作,SpringBoot 版本需要与 ES 版本对应,否则会报错!
请添加图片描述

Java 集成 ES 官方文档

索引操作

  1. 创建索引

    // 官方文档Demo
    // Create the low-level client
    RestClient restClient = RestClient.builder(
        new HttpHost("localhost", 9200)).build();
    
    // Create the transport with a Jackson mapper
    ElasticsearchTransport transport = new RestClientTransport(
        restClient, new JacksonJsonpMapper());
    
    // And create the API client
    ElasticsearchClient client = new ElasticsearchClient(transport);
    
    // Create the "products" index
    client.indices().create(c -> c.index("products"));
    
  2. 索引存在与否

    BooleanResponse response = elasticsearchClient.indices().exists(c -> c.index("products"));
    System.out.println(response.value());
    
  3. 删除索引

    DeleteIndexResponse response = elasticsearchClient.indices().delete(c -> c.index("products"));
    System.out.println(response);
    

文档操作

  1. 添加文档

    • 单条数据添加(若文档不存在会创建)

      // 创建对象
      User user1 = new User("xiaoming_001", 20);
      User user2 = new User("xiaoming_002", 23);
      User user3 = new User("xiaoming_003", 24);
      
      // 1.方式一
      // i indexRequest.Builder
      IndexResponse response = elasticsearchClient.index(i -> i
                                                         // 索引名称
                                                         .index("user_index")
                                                         // 设置document id
                                                         .id("2")
                                                         .document(user1)
                                                        );
      System.out.println(response.version());
      
      // 2.方式二
      IndexRequest<User> request = IndexRequest.of(i -> i
                                                   .index("user_index")
                                                   .id("3")
                                                   .document(user2)
                                                  );
      IndexResponse indexResponse = elasticsearchClient.index(request);
      System.out.println(indexResponse);
      
      // 3.方式三
      IndexRequest.Builder<User> userBuilder = new IndexRequest.Builder<>();
      userBuilder.index("user_index")
          .id("4")
          .timeout(Time.of(t -> t.time("1s")))
          .document(user3);
      IndexResponse resp = elasticsearchClient.index(userBuilder.build());
      System.out.println(resp);
      
    • 多条数据添加

      BulkRequest.Builder brBuilder = new BulkRequest.Builder();
      List<User> userList = new ArrayList<>();
      userList.add(new User("xiaoming_001", 1));
      userList.add(new User("xiaoming_002", 2));
      userList.add(new User("xiaoming_003", 3));
      userList.add(new User("xiaoming_004", 4));
      userList.add(new User("Lihua_001", 5));
      userList.add(new User("Lihua_002", 15));
      userList.add(new User("Lihua_003", 25));
      for (int i = 0; i < userList.size(); i++) {
          int finalI = i;
          brBuilder.operations(op -> op
                               .index(idx -> idx
                                      .index("idea_levin_index")
                                      .document(userList.get(finalI)
                                               )
                                     )
                              );
      }
      
  2. 文档查询

    // 通过id查询
    public void testSearchDocumentById() throws IOException {
        // 第一个参数为request请求 第二个参数为json映射成的类
        GetResponse<User> resp = elasticsearchClient.get(g -> g
                                                         .index("idea_levin_index")
                                                         .id("2"),
                                                         User.class);
    
        if (resp.found()) {
            User user = resp.source();
            assert user != null;
            System.out.println("User: "+user.toString());
        }
    }
    
    // 条件查询查询多条文档
    public void testSearchDocuments() throws IOException {
            SearchResponse<User> resp = elasticsearchClient.search(s -> s
                            // 搜索的索引名称
                            .index("idea_levin_index")
                            // 搜索请求的查询部分
                            .query(q -> q
                                    // 选择查询体,此处选择匹配查询(全文搜索)
                                    .match(t -> t
                                            // 配置匹配查询,字段中搜索一个词
                                            .field("name")
                                            .query("xxx")
                                    )
                            ),
                    // 匹配文档的目标类
                    User.class);
    
            List<Hit<User>> hits = resp.hits().hits();
            System.out.println(hits);
            TotalHits total = resp.hits().total();
            assert total != null;
            System.out.println(total.value());
        }
    
    // 搜索体查询
    void TestSearchQueries() throws IOException {
            // 构建搜索体
            // MatchQuery by name
            Query queryByName = MatchQuery.of(m -> m
                    .field("name")
                    .query("Levin")
            )._toQuery();
            // RangeQuery by age
            Query qeuryByAge = RangeQuery.of(m -> m
                    .field("age")
                    .gte(JsonData.of(3))
            )._toQuery();
            // search the index
            SearchResponse<User> resp = elasticsearchClient.search(s -> s
                            .index("idea_levin_index")
                            .query(q -> q
                                    .bool(b -> b
                                            .must(queryByName)
                                            .must(qeuryByAge)
                                    )
                            ),
                    User.class
            );
            List<Hit<User>> hits = resp.hits().hits();
            System.out.println(hits);
            assert resp.hits().total() != null;
            System.out.println(resp.hits().total().value());
        }
    

实战演示

此实战使用的Demo来自狂神的讲解,感谢狂神!

代码存放于我的 gitee 仓库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

programming_rooike

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值