elasticsearch-核心知识

237 阅读12分钟

1. elasticsearch的核心概念

  • 什么是elasticsearch

es基于lucence,隐藏复杂性,提供简单易用的restful api接口、java api接口(还有其它语言的api接口),es是一个实时分布式搜索和分析引擎,它用于全文搜索、结构化搜索、分析

  • 近实时 从写入数据到可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级(倒排索引)

  • Cluster(集群) 集群包含多个节点,每个节点属于哪个集群是通过一个配置来决定的。对于中小型应用,刚开始一个集群一个节点是正常的

  • Node(节点) 集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为elasticsearch的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群

  • Index (索引) 索引包含一堆相识结构的文档数据,类比关系型数据库的库

  • Type (类型) 每个索引都可以会有一个或多个Type,type是index中的一个逻辑数据分类,类型类别关系型数据库的表table, 在6.x的版本中是支持type , 但是在7.x的版本中的type都是_doc类型了,在8.x是打算完全去掉type类

  • Document(文档) 文档是es中的最小数据单元,一个document可以是一条客户数据、一条订单数据,类比关系型数据库的行row

  • Field(字段) field是es的最小单位。一个document里有多个field,每个field就是一个数据字段,类比关系型数据库的字段

  • Mapping(映射) 数据如何存放到索引对象上,需要有一个映射配置,类比关系型数据库的schame

  • Shards(分片) 因为ES是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片. ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节,一个分片默认最大文档数量是20亿

  • Replica(副本) ES默认为一个索引创建5个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由5个主分片成本, 而每个主分片都相应的有一个copy

2. curl命令&kibana开发者工具

2.1 curl命令

  • curl介绍 CURL命令简单可以认为是在命令行下访问url的一个工具,是利用URL语法在命令行方式下工作的开源文件传输工具,使用curl可以简单实现常见的get/post请求

  • curl的格式 –curl -X请求类型 请求Url -d '数据'

详细curl命令的讲解可以参考:curl使用操作

  • curl操作elasticsearch 因为es的操作符合RESTfull风格,所以可以根据curl对es进行操作
# 如创建索引
curl -XPUT  http://192.168.64.129:9200/index11?pretty

# 如删除索引
curl -XDELETE  http://192.168.64.129:9200/index11?pretty

image.png

image.png

2.2 kibana开发者工具

调试elasticsearch也可以采用kibana的开发者工具,这个是调试elasticsearch的最常见的方法

image.png

如果没有搭建elasticsearch集群和kibana的同学可以参考:

3. 索引管理

ES索引管理API主要包含如下API:

  • Create Index 创建索引:
PUT /index
{
    "settings" : {                 //@1
        "number_of_shards" : 1
    }, 
    "mappings" : {                // @2
        "_doc" : {
            "properties" : {
                "field1" : { "type" : "text" }
            }
        }
    },
    "aliases" : {                  // @3
        "alias_1" : {},
        "alias_2" : {
            "filter" : {
                "term" : {"user" : "kimchy" }
            },
            "routing" : "kimchy"
        }
    }
}

创建索引采用PUT请求

代码@1:索引的配置属性
代码@2:定义映射,有点类似于关系型数据库中的定义表结构
代码@3:为索引指定别名设置

注意:创建已经存在的索引是要报错的。

  • Delete Index 删除索引:
PUT /index

删除索引采用DELETE请求,操作比较简单

  • Get index 获取索引:
GET /index

获取索引比较简单

  • 查看索引列表
GET /_cat/indices?v

image.png

  • 更新副本数量
PUT /index/_settings
{
  "number_of_replicas": 1
}
  • 查看索引配置
GET /index/_settings

4. term & match_all 查询

  • term查询
#  插入一条数据
PUT /index/_doc/1
{
  "name":"中国人",
  "code":"CHN"
  
}

# 通过term词项查询name字段
GET /index/_search
{
  "query": {
    "term": {
      "name": {
        "value": "国"
      }
    }
  },
  "from": 0,
  "size": 1,
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

image.png

对于保存在es中的词语,默认采用了分词处理,如:“中国人”,或采才分为“中”,“国”,“人” 三个词项,那么在使用term查询name字段的时候带一个“国”字也是能查询出来的。

注意:如果需要进行分页查询则可以带上fromsize者两个字段进行分页操作,如果需要进行高亮处理着添加highlight标识即可

  • match_all 看这个查询就能看出来,这个是一个查询全部数据的方法
GET /index/_search
{
  "query": {
    "match_all": {}
  }
}

5. range & exists 查询

  • range查询 听这个名字就能听出来,这个是一个范围查询的方法操作比较简答如下:
# range查询age大于等于30 并且 小于等于100 的数据
GET /index/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 30,
        "lte": 100
      }
    }
  }
}

其中range查询可以接受的参数为:

gte:大于等于
gt:大于
lte:小于等于
lt:小于
boost:设置查询的推动值(boost),默认为1.0

  • exists查询 exists查询的是某一条数据中包含某一个字段
# 判断index索引中包含由age字段的数据
GET /index/_search
{
  "query": {
    "exists": {
      "field": "age"
    }
  }
}

6. match 查询

# 采用match查询name字段查询

GET /index/_search
{
  "query": {
    "match": {
      "name": "中李"
    }
  }
}

image.png

解释:其中查询的name字段的内容“中李”会被分词器分为“中”,“李”两个词,只要数据中包含有中李两个字的数据都会被查询出来。所以使用match查询的时候会把查询内容进行分词后进行查询

7. bool查询

为什么需要采用bool查询,因为采用bool查询可以很轻松的查询多个数据的子集,可以进行一些过滤操作,在电商的多条件搜索的时候会使用到。

bool查询主要由以下几种组成:

must:[] : 返回的文档必须满足must子句的条件,并且参与计算分值

filter:[] : 返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值

should:[] : 返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match参数定义了至少满足几个子句。

must_nout:[] : 返回的文档必须不满足must_not定义的条件

7.1 bool.must计算

# 搜索index索引下面的数据,采用must查询同时满足name查询 和 age查询两个条件的交集

GET /index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "中李美"
          }
        },
        {
          "range": {
            "age": {
              "gte": 30,
              "lte": 100
            }
          }
        }
      ]
    }
  }
}

image.png

解释:must查询中包含两个查询条件match 和 range两个条件,这个查询是求的两个数据集的子集,并且数据中带有_score分数值,这个分数值越大表明匹配强度越高

7.2 bool.filter计算

# 这个地方采用了bool查询 和 filter查询,这个地方查询的数据和7.1中的查询数据是一致的,唯一不同的就是filter过滤的数据不参与分数_score计算

GET /index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "中李美"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "age": {
              "gte": 30,
              "lte": 100
            }
          }
        }
      ]
    }
  }
}

filter的过滤和must过滤查询的效果是一样的,只是不参与分数计算

7.3 bool.must_not计算

# 该计算是求: must(数据) - must_not(数据) = 差集数据

GET /index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "中国李美"
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "age": {
              "gte": 30,
              "lte": 100
            }
          }
        }
      ]
    }
  }
}

image.png

解释:可以看到查询出来的数据中,满足了must条件,但是不包含must_not条件中的数据。验证了求的是数据的差集,往往会用到查询了某一批数据后,需要过滤其中一批数据的场景.

7.4 bool.should计算

# 该计算中:包含了满足name条件 或者 age条件的都会查询出来

GET /index/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "中"
          }
        },
        {
          "range": {
            "age": {
              "gte": 30,
              "lte": 60
            }
          }
        }
      ]
    }
  }
}

解释:should条件是或的关系,只要满足其中一项都会被查询出来

image.png

8. 动态mapping

Elasticsearch的一个最重要的特性是,让你尽可能快地开始探索数据。要为文档建立索引,您不必首先创建索引、定义映射类型和定义字段,你只需创建文档,就会自动创建索引,索引、类型和字段。自动为类型映射根据文档的值推测其类型的过程,就是本文要重点描述的机制:动态类型映射机制。

  • 如果遇到新字段,对象就会抛出异常
  • 而内部对象 stash 遇到新字段就会动态创建新字段

动态映射机制包含如下两种映射规则:Dynamic field mappings、Dynamic templates

8.1 Dynamic field mappings

动态字段映射规则。默认情况下,当在文档中发现以前未见过的字段时,Elasticsearch将向类型映射添加新字段

JSON datatypeElasticsearch datatype
null不会自动增加类型映射
true or falseboolean
floating point numberfloat
integerlong
objectobject
array根据数组中第一个非空值来判断
stringdate、double、long、text(带有keyword子字段)

8.2 Dynamic templates

Dynamic field mappings默认情况下是根据elasticsearch支持的数据类型来推测参数值的类型,而动态模板允许您定义自定义映射规则,根据自定义的规则来推测字段值所属的类型,从而添加字段类型映射.

PUT /index
{
    "mappings": {
        "index": {
            "dynamic_templates": [
                { "es": {
                      "match":              "*_es",  //@1
                      "match_mapping_type": "string",
                      "mapping": {
                          "type":           "string",
                          "analyzer":       "spanish"
                      }
                }},
                { "en": {
                      "match":              "*",  //@2
                      "match_mapping_type": "string",
                      "mapping": {
                          "type":           "string",
                          "analyzer":       "english"
                      }
                }}
            ]
}}}

@1:匹配字段名以 _es 结尾的字段
@2:匹配其他所有字符串类型字段

9. 静态mapping

静态mapping主要包括如下的一些字段,这里只列举部分字段。

9.1 修改mapping

PUT /index/_mapping
{
  "properties" : {
    "age" : {
      "type" : "long"
    },
    "name" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "email":{
      "type": "keyword"
    },
    "is_handle":{
      "type": "boolean"
    }
  }
}

9.2 主要字段

  • 整型long
  • 字符串text (text是会被分词)
  • boolean
  • date
  • keyword (keyword是不会进行分词的,如搜素email或者电话之类)
"name" : {
  "type" : "text",
  "fields" : {
    "keyword" : {
      "type" : "keyword",
      "ignore_above" : 256
    }
  }
}

# 解释:其中text为name字段的类型,keyword为其扩展属性,只要不超过256字符也会用keyword进行索引一次,保证精准匹配也能匹配到

其中keyword的搜素方式如下:

# keyword的搜素方式需要在name搜素的后面添加keyword进行搜素

GET /index/_search
{
  "query": {
    "term": {
      "name.keyword": {
        "value": "中国人"
      }
    }
  }
}

其他详情介绍请查:官方字段文档

10. 分片 & 副本

  • 查看索引的分片
GET /index/_settings

image.png

其中的number_of_shards为当前索引的分片数量,number_of_replicas为副本数量

  • 设置分片和副本的数量 在创建索引的时候就可以设置分片数量:
PUT /test_index
{
  "settings" : {
    "index" : {
      "number_of_shards" : 2,
      "number_of_replicas" : 2
    }
  }
}
  • 修改副本数量
PUT /test_index/_settings
{
  "index":{
    "number_of_replicas" : "3"
  }
}

11. 分词器

11.1 默认分词器

  • 概念 Analysis(分词):文本分析是把全文本转换一系列单词(term/token)的过程,也叫分词,Analysis是通过Analyzer来实现的。
    analyzer(分析器): 由三种构件块组成的:character filters , tokenizers , token filters

character filter字符过滤器:在一段文本进行分词之前,先进行预处理,比如说最常见的就是,过滤html标签(hello --> hello),& --> and(I&you --> I and you)
tokenizers分词器:英文分词可以根据空格将单词分开,中文分词比较复杂,可以采用机器学习算法来分词
Token filters Token过滤器:将切分的单词进行加工,大小写转换(例将“Quick”转为小写),去掉词(例如停用词像“a”、“and”、“the”等等),或者增加词(例如同义词像“jump”和“leap”)

三者顺序Character Filters--->Tokenizer--->Token Filter
三者个数analyzer = CharFilters(0个或多个) + Tokenizer(恰好一个) + TokenFilters(0个或多个)

  • Elasticsearch的内置分词器

Standard Analyzer - 默认分词器,按词切分,小写处理
Simple Analyzer - 按照非字母切分(符号被过滤), 小写处理
Stop Analyzer - 小写处理,停用词过滤(the,a,is)
Whitespace Analyzer - 按照空格切分,不转小写
Keyword Analyzer - 不分词,直接将输入当作输出
Patter Analyzer - 正则表达式,默认\W+(非字符分割)
Language - 提供了30多种常见语言的分词器
Customer Analyzer 自定义分词器

11.2 分词分析

POST _analyze
{
  "analyzer": "standard",
  "text":     "Like X 国庆放假的"
}

image.png

11.4 ik分词器

中文的分词器现在大家比较推荐的就是 IK分词器

将下载的ik包解压复制到es安装的plugins目录下面即可,再重新启动es就会加载对于的文件

  • 使用 ik_smart: 会做最粗粒度的拆分

image.png

ik_max_word: 会将文本做最细粒度的拆分 image.png

11.5 热词配置

进入es的plugins目录的ik分词器的config目录

[root@localhost config]# cd /data/elasticsearch-7.15.0/plugins/ik/config/
[root@localhost config]# 
[root@localhost config]# cat IKAnalyzer.cfg.xml 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">extar_my.dic</entry>
        
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords">stop_my.dic</entry>
        
	<!--用户可以在这里配置远程扩展字典 -->
	 <entry key="remote_ext_dict">http://192.168.64.129/hot.dic</entry>
         
	<!--用户可以在这里配置远程扩展停止词字典-->
	<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
[root@localhost config]# 

  • 扩展热词

image.png

在目录下添加extar_my.dic文件,内容为可以自定义,然后再修改IKAnalyzer.cfg.xml 文件将配置的热词添加到配置文件中

<entry key="ext_stopwords">extar_my.dic</entry>
  • 停用词 image.png

在目录下添加stop_my.dic文件,内容为可以自定义,然后再修改IKAnalyzer.cfg.xml 文件将配置的热词添加到配置文件中, 添加了停用词典则词典中的词语将不再进行分词

<entry key="ext_stopwords">stop_my.dic</entry>
  • 远程加载热词

加载一个远程的词典文件,es会隔几秒钟,就会去拉起远程文件加载进去,所以如果有热词跟新,只需要修改远程文件中的热词即可,无需重启es.

<entry key="remote_ext_dict">http://192.168.64.129/hot.dic</entry>