1. ElasticSearch

ElasticSearch是基于 Lucene的搜索服务器 是一个分布式 高扩展 高实时的搜索与数据分析引擎

基于RESTful web接口

ElasticSearch是用java开发 并作为apache的开源项目

https://www.elastic.co/cn/

一般用于 海量数据的查询 日志数据分析 实时数据分析

2. 倒排索引

将各个文档中内容.进行分词 形成词条 记录词条和数据的唯一标识(id)的对应关系 形成的产物

3. ElasticSearch搜索和传统数据库查询的区别

  1. 传统关系型数据 使用模糊查询 左边有通配符 不会走索引 会全表扫描 性能低
  2. 只能以一个关键字作为查询条件 而ElasticSearch会把一个关键字拆分为多个词 进行查询
  3. ElasticSearch 以关键字 生成的倒排索引 词条会排序 形成一颗树形结构 提升词条的查询速度
  4. Mysql有事务性 而ElasticSearch 没有事务性 所以删了的数据是无法恢复的
  5. ElasticSearch 没有物理外键这个特性 如果数据的一致性要求比较高 不建议使用
  6. ElasticSearch和Mysql 分工不同 Mysql负责存储数据 ElasticSearch负责搜索数据

4. 安装ElasticSearch

  1. tar -zxvf elasticsearch-7.15.0-linux-x86_64.tar.gz -C /opt
  2. #编辑配置
  3. vim /opt/elasticsearch-7.15.0/config/elasticsearch.yml
  4. #追加以下内容
  5. cluster.name: my-application
  6. node.name: node-1
  7. network.host: 0.0.0.0
  8. http.port: 9200
  9. cluster.initial_master_nodes: ["node-1"]
  10. #出于安全问题ElasticSearch不允许root用户直接运行
  11. useradd iekr
  12. passwd 123456
  13. #授权
  14. chown -R iekr:iekr /opt/elasticsearch-7.15.0/

新建的用户最大创建文件和最大虚拟内存太小 需要修改配置文件

  1. #修改最大创建文件数
  2. vim /etc/security/limits.conf
  3. #追加内容
  4. iekr soft nofile 65536
  5. iekr hard nofile 65536
  6. vim /etc/security/limits.d/20-nproc.conf
  7. #追加内容
  8. iekr soft nofile 65536
  9. iekr hard nofile 65536
  10. * hard nproc 4096
  11. #修改虚拟内容大小
  12. vim /etc/sysctl.conf
  13. #追加内容
  14. vm.max_map_count=655360
  15. #重载
  16. sysctl -p
  17. firewall-cmd --zone=public --add-port=9200/tcp --permanent

启动

  1. su iekr
  2. cd /opt/elasticsearch-7.15.0/bin/
  3. ./elasticsearch -d #-d后台运行

访问 http://192.168.130.124:9200/ 出现json字符串则启动成功

4.1. 安装辅助工具Kibana

https://www.elastic.co/cn/kibana/

  1. tar -zxvf kibana-7.15.0-linux-x86_64.tar.gz -C /opt
  2. #配置
  3. vim /opt/kibana-7.15.0-linux-x86_64/config/kibana.yml
  4. #追加内容
  5. server.port: 5601
  6. server.host: "0.0.0.0"
  7. server.name: "your-hostname" #自定义名称
  8. elasticsearch.hosts: ["http://localhost:9200"]
  9. elasticsearch.requestTimeout: 30000 #连接ES超时时间
  10. i18n.locale: "zh-CN" #设置为中文
  11. #授权
  12. chown -R iekr:iekr /opt/kibana-7.15.0-linux-x86_64/
  13. firewall-cmd --zone=public --add-port=5601/tcp --permanent

启动

  1. su iekr
  2. cd /opt/kibana-7.15.0-linux-x86_64/bin/
  3. nohup ./kibana & #后台运行 前台./kibana

5. ElasticSearch 核心概念

  • 索引(index)
    ElasticSearch存储数据的地方 可以理解为关系型数据库中的数据库概念

  • 映射(mapping)
    mapping定义了每个字段的类型 字段所使用的分词器等 相定义关系型数据库中的表结构

  • 文档(document)
    ElasticSearch中的最小数据单元 以json格式显示 一个document相当于 关系型数据库的一行数据

  • 倒排索引
    一个倒排索引由文档中所有不重复此的列表构成 对应其中每个词 对应一个包含它的文档id列表

  • 类型(type)
    一种type就像一类表 如用户表 角色表等
    在ElasticSearch7.x type默认为_doc
    5.x中一个index可以有多种type
    6.x中一个index只能有一种type

6. 操作ElasticSearch

6.1. RESTful风格

REST 表述性状态转移 是一组架构约束条件和原则 满足这些约束条件和原则的应用程序或设计就是RESTful 是与只能怪定义接口的规范

6.2. 操作索引

以下操作使用postman工具发送请求

6.2.1. 添加索引

使用PUT请求 在uri地址后加上索引名称

  1. 192.168.130.124:9200/goods_index

6.2.2. 查询索引

使用GET请求 在uri地址后加上索引名称

  1. 192.168.130.124:9200/goods_index

查询多个使用逗号分隔

  1. 192.168.130.124:9200/goods_index,goods_index2

查询全部使用_all

  1. 192.168.130.124:9200/_all

6.2.3. 删除索引

使用DELETE请求 在uri地址后加上索引名称

  1. 192.168.130.124:9200/goods_index

6.2.4. 关闭指定索引

关闭后只是无法使用 并不会删除此索引

  1. 192.168.130.124:9200/goods_index/_close

打开索引

  1. 192.168.130.124:9200/goods_index/_open

6.3. 操作映射

  • 简单数据类型

    • 字符串

      • text 会分词,不支持聚合
      • keyword 不会分词 将全部内容作为一个词条 支持聚合
    • 数组

      • 18. ElasticSearch - 图1
    • 布尔
    • 二进制

      • binary
    • 范围类型

      • integer_range
      • float_range
      • long_range
      • double_range
      • date_range
    • 日期
  • 复杂数据类型

    • 数组:[]
    • 对象:{}

6.3.1. 添加映射

以下操作使用Kibana操作

http://192.168.130.124:5601/app/dev_tools#/console

  1. # 创建索引
  2. PUT person
  3. # 查询索引
  4. GET person
  5. # 添加映射
  6. PUT person/_mapping
  7. {
  8. "properties":{
  9. "name":{
  10. "type":"keyword"
  11. },
  12. "age":{
  13. "type":"integer"
  14. }
  15. }
  16. }
  17. # 查询映射
  18. GET person/_mapping
  19. # 删除索引
  20. DELETE person
  21. # 创建索引并添加映射
  22. PUT person
  23. {
  24. "mappings": {
  25. "properties": {
  26. "name":{
  27. "type":"keyword"
  28. },
  29. "age":{
  30. "type":"integer"
  31. }
  32. }
  33. }
  34. }
  35. # 查询索引
  36. GET person
  37. # 添加字段
  38. PUT person/_mapping
  39. {
  40. "properties":{
  41. "address":{
  42. "type":"text"
  43. }
  44. }
  45. }

6.4. 操作文档

  1. # 查询索引
  2. GET person
  3. # 添加文档 指定id 可以使用PUT或POST请求
  4. PUT person/_doc/1
  5. {
  6. "name":"zhangsan",
  7. "age":20,
  8. "address":"北京"
  9. }
  10. # 添加文档 不指定id 必须为POST请求
  11. POST person/_doc
  12. {
  13. "name":"李四",
  14. "age":30,
  15. "address":"广东"
  16. }
  17. # 根据id查询文档
  18. GET person/_doc/1
  19. # 查询所有文档
  20. GET person/_search
  21. # 修改文档 必须为PUT请求 如果id存在则修改 不存在则自动创建
  22. PUT person/_doc/1
  23. {
  24. "name":"wangwu",
  25. "age":20,
  26. "address":"北京"
  27. }
  28. # 根据ID删除文档
  29. DELETE person/_doc/1

7. 分词器

18. ElasticSearch - 图2

但ES原始的分词器对中文不太友好

8. IK分词器

IKAnalyzer是一个开源的 基于java语言开发的轻量级的中文分词工具包

是一个基于Maven构建的项目 具有60万字/秒的高速处理能力 支持用户词典扩展定义

https://github.com/medcl/elasticsearch-analysis-ik

8.1. 安装

  • 安装JDK 由于ES内置了JDK 我们将ES内置的JDK设置为系统环境变量
  1. vim /etc/profile
  2. export JAVA_HOME=/opt/elasticsearch-7.15.0/jdk
  3. export PATH=$PATH:${JAVA_HOME}/bin
  4. source /etc/profile
  • 安装Maven — 已不需要
  1. wget https://mirrors.bfsu.edu.cn/apache/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.tar.gz
  2. tar -zxvf apache-maven-3.8.3-bin.tar.gz
  3. ln -s apache-maven-3.8.3 maven
  4. #配置环境变量
  5. vim /etc/profile.d/maven.sh
  6. export MAVEN_HOME=/root/maven
  7. export PATH=${MAVEN_HOME}/bin:${PATH}
  8. source /etc/profile.d/maven.sh
  9. mvn -v
  • 安装IK分词器 —已不需要
  1. wget https://github.com/medcl/elasticsearch-analysis-ik/archive/refs/tags/v7.15.0.zip #这里下载的是源码
  2. # 由于是zip文件所以需要unzip命令
  3. yum install -y zip
  4. yum install -y unzip
  5. #解压
  6. unzip v7.15.0.zip
  7. cd /root/elasticsearch-analysis-ik-7.15.0/
  8. #编译打包
  9. mvn package
  • 将编译好的插件导入到ES中
  1. cd /opt/elasticsearch-7.15.0/plugins/
  2. mkdir analysis-ik
  3. cd analysis-ik/
  4. #重启es

8.2. 使用

  1. # ES内置分词器
  2. GET _analyze
  3. {
  4. "analyzer": "standard",
  5. "text": "你是试试水"
  6. }
  7. # ik分词器,粗粒度分词
  8. GET _analyze
  9. {
  10. "analyzer": "ik_smart",
  11. "text": "你是试试水"
  12. }
  13. # ik分词器,粗粒度分词
  14. GET _analyze
  15. {
  16. "analyzer": "ik_max_word",
  17. "text": "你是试试水"
  18. }

8.2.1. 查询文档

  • 词条查询:tern

    • 词条查询不会分析查询条件 只有当词条和查询字符串完全匹配时才匹配搜索
  • 全文查询:match

    • 全文查询会分析查询条件 先将查询条件进行分词 然后查询 求并集
  1. PUT person/_doc/2
  2. {
  3. "name":"李四",
  4. "age":30,
  5. "address":"华为5G手机"
  6. }
  7. GET person/_doc/2
  8. # term 词条查询 查询条件字符串和词条要完全匹配
  9. # es默认使用的分词器是standard 一个子一个词
  10. GET person/_search
  11. {
  12. "query":{
  13. "term": {
  14. "address": {
  15. "value": "手机"
  16. }
  17. }
  18. }
  19. }
  20. DELETE person
  21. # 创建索引 添加映射 指定使用ik分词器
  22. PUT person
  23. {
  24. "mappings": {
  25. "properties": {
  26. "name":{
  27. "type": "keyword"
  28. },
  29. "address":{
  30. "type": "text",
  31. "analyzer": "ik_max_word"
  32. }
  33. }
  34. }
  35. }
  36. GET person
  37. # 添加文档
  38. PUT person/_doc/1
  39. {
  40. "name":"张三",
  41. "age":30,
  42. "address":"华为5G手机"
  43. }
  44. PUT person/_doc/2
  45. {
  46. "name":"李四",
  47. "age":30,
  48. "address":"广东"
  49. }
  50. PUT person/_doc/3
  51. {
  52. "name":"王五",
  53. "age":30,
  54. "address":"小米5G手机"
  55. }
  56. GET person/_search
  57. # 查询 term词条查询
  58. GET person/_search
  59. {
  60. "query":{
  61. "term": {
  62. "address": {
  63. "value": "手机"
  64. }
  65. }
  66. }
  67. }
  68. # match 先会对查询的字符串进行分词 在查询 求交集
  69. GET person/_search
  70. {
  71. "query": {
  72. "match": {
  73. "address": "苹果手机"
  74. }
  75. }
  76. }

9. JavaApi

  1. 创建springboot项目 并引入ES
    18. ElasticSearch - 图3

  2. 创建application.yml 配置文件

    1. elasticsearch:
    2. host: 192.168.130.124
    3. port: 9200
  1. 创建ElasticSearchConfig配置类 加载配置文件 并返回一个es客户端对象 ```java package com.itheima.elasticsearchdemo.config;

import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

@Configuration @ConfigurationProperties(prefix = “elasticsearch”) public class ElasticSearchConfig {

  1. private String host;
  2. private int port;
  3. public String getHost() {
  4. return host;
  5. }
  6. public void setHost(String host) {
  7. this.host = host;
  8. }
  9. public int getPort() {
  10. return port;
  11. }
  12. public void setPort(int port) {
  13. this.port = port;
  14. }
  15. @Bean
  16. public RestHighLevelClient client(){
  17. return new RestHighLevelClient(RestClient.builder(
  18. new HttpHost(host,port,"http")
  19. ));
  20. }

}

  1. 4.
  2. 注入对象 使用
  3. ```java
  4. //1.创建es客户端对象
  5. @Autowired
  6. private RestHighLevelClient restHighLevelClient;

9.1. 添加索引

  1. //添加索引
  2. @Test
  3. void addIndex() throws IOException {
  4. //获取操作索引的对象
  5. IndicesClient indices = restHighLevelClient.indices();
  6. //添加
  7. CreateIndexRequest createIndex = new CreateIndexRequest("itheima"); //索引名称
  8. CreateIndexResponse createIndexResponse = indices.create(createIndex, RequestOptions.DEFAULT);
  9. //根据返回值判断结果
  10. System.out.println(createIndexResponse.isAcknowledged());
  11. }
  • 添加索引并添加映射
  1. //添加索引并添加映射
  2. @Test
  3. void addIndexAndMapping() throws IOException {
  4. //获取操作索引的对象
  5. IndicesClient indices = restHighLevelClient.indices();
  6. CreateIndexRequest request = new CreateIndexRequest("twitter");
  7. // 向索引添加映射
  8. request.source("{\n" +
  9. " \"settings\" : {\n" +
  10. " \"number_of_shards\" : 3,\n" +
  11. " \"number_of_replicas\" : 2\n" +
  12. " },\n" +
  13. " \"mappings\" : {\n" +
  14. " \"tweet\" : {\n" +
  15. " \"properties\" : {\n" +
  16. " \"message\" : { \"type\" : \"text\" }\n" +
  17. " }\n" +
  18. " }\n" +
  19. " },\n" +
  20. " \"aliases\" : {\n" +
  21. " \"twitter_alias\" : {}\n" +
  22. " }\n" +
  23. "}", XContentType.JSON);
  24. CreateIndexResponse createIndexResponse = indices.create(request, RequestOptions.DEFAULT);
  25. //根据返回值判断结果
  26. System.out.println(createIndexResponse.isAcknowledged());
  27. }

6.2.2. 查询索引

  1. //查询索引
  2. @Test
  3. public void queryIndex() throws IOException {
  4. GetIndexRequest request = new GetIndexRequest("twitter");
  5. GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
  6. System.out.println(getIndexResponse.getAliases());
  7. System.out.println(getIndexResponse.getMappings());
  8. }

6.2.3. 删除索引

  1. //删除索引
  2. @Test
  3. public void deleteIndex() throws IOException {
  4. IndicesClient indices = restHighLevelClient.indices();
  5. DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("itheima");
  6. AcknowledgedResponse acknowledgedResponse = indices.delete(deleteIndexRequest, RequestOptions.DEFAULT);
  7. System.out.println(acknowledgedResponse.isAcknowledged());
  8. }

9.1.3. 判断索引是否存在

  1. //判断索引是否存在
  2. @Test
  3. public void existIndex() throws IOException {
  4. IndicesClient indices = restHighLevelClient.indices();
  5. GetIndexRequest getRequest = new GetIndexRequest("itheima");
  6. boolean exists = indices.exists(getRequest, RequestOptions.DEFAULT);
  7. System.out.println(exists);
  8. }

9.2. 添加/修改文档

当id存在时则修改 不存在时则添加

9.2.1. Map

  1. //添加/修改 map
  2. @Test
  3. public void addDoc() throws IOException {
  4. //添加数据对象 map
  5. Map<String, String> data = new HashMap<>();
  6. data.put("address","背景");
  7. data.put("name","钻石");
  8. data.put("age","11");
  9. //1.获取文档对象
  10. IndexRequest indexRequest = new IndexRequest("twitter").id("1").source(data);
  11. //添加数据
  12. IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
  13. //打印响应结果
  14. System.out.println(index.getId());
  15. }

9.2.2. JSON

  1. //添加/修改 json
  2. @Test
  3. public void addDoc2() throws IOException {
  4. //创建对象
  5. Person p =new Person();
  6. p.setId("2");
  7. p.setName("iekr");
  8. p.setAge(15);
  9. p.setAddress("广东");
  10. String json = JSON.toJSONString(p);
  11. //1.获取文档对象
  12. IndexRequest indexRequest = new IndexRequest("twitter").id(p.getId()).source(json,XContentType.JSON);
  13. //添加数据
  14. IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
  15. //打印响应结果
  16. System.out.println(index.getId());
  17. }

9.3. 查询文档

  1. //根据id查询文档
  2. @Test
  3. public void findDocById() throws IOException {
  4. GetRequest getRequest = new GetRequest("twitter", "1");
  5. // getRequest.id("1"); //单独指定id
  6. GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
  7. System.out.println(documentFields.getSourceAsString()); //获取JSON字符串
  8. }

9.4. 删除文档

  1. //根据id删除文档
  2. @Test
  3. public void delDoc() throws IOException {
  4. DeleteRequest delete = new DeleteRequest("twitter", "1");
  5. DeleteResponse response = restHighLevelClient.delete(delete, RequestOptions.DEFAULT);
  6. System.out.println(response.getId());
  7. }