Elasticsearch超详细笔记

it2024-05-06  50

Elasticsearch超详细笔记

引言:

          本文主要分享了有关Elasticsearch(简称ES)的知识,包括:ES的简介、基本概念、倒序索引、ES的安装以及使用、Kibana可视化工具的安装与使用、分词的使用、使用可视化工具Kibana实现索引和文档的增删查改、以及一些高级的ES查询,如:批量获取文档信息、使用Bulk API实现批量操作、采用乐观锁机制实现并发控制、Mapping、通用查询(分词查找、短语查询、返回指定字段、高亮查询、范围查询 )、Bool过滤查询、范围查询、聚合查询等等;

文章目录

Elasticsearch超详细笔记1. Elasticsearch简介 1.1 衍生的开源软件1.2 ES特性1.3 ES核心概念1.4 结构化数据与非结构化数据1.5 倒排索引 2. ES的安装使用 2.1 安装2.2 启动2.3 ES端口2.4 可视化工具Kibana 2.4.1 下载安装Kibana2.4.2 配置2.4.3 启动Kibana 2.5 集成Ikanalyzer 2.5.1 下载安装Ikanalyzer2.5.2 两种分词模式2.5.3 测试分词_细粒度拆分2.5.4 测试分词_粗粒度拆分2.5.5 自定义分词库 3. 使用Kibana实现增删查改 3.1 创建索引3.2 查看索引3.3 添加文档3.4 查询文档3.5 修改文档3.6 删除文档 4. 批量获取文档信息 4.1 获取多个索引下面的多个文档对象4.2 指定具体的字段4.3 简化批量获取的方式 5. 使用Bulk API实现批量操作 5.1 批量添加5.2 批量查询5.3 批量删除5.4 注意事项 6. 采用乐观锁机制实现并发控制 6.1 内部版本6.2 外部版本 7. Mapping8. 通用查询 8.1 准备数据8.2 精确查找 8.2.1 查询某个字段里含有某个关键词的文档8.2.2 查询某个字段里含有多个关键词的文档 8.3 设值返回的条数8.4 设值返回的版本8.5 分词查找8.6 指定多个字段进行查询8.7 短语查询8.8 指定返回的字段8.9 排序8.10 前缀匹配8.11 范围查询8.12 通配符8.13 高亮查询 9. Bool过滤查询10. 范围查找11. 聚合查询 11.1 求和11.2 最小值11.3 最大值11.4 平均值11.5 求基数11.6 分组

1. Elasticsearch简介

          Elasticsearch 是一个开源的搜索引擎, 建立在全文搜索引擎库 Apache Lucene 基础上;内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTFUL API;

Elasticsearch 不仅仅只是一个全文搜索引擎是一个分布式的实时文档存储,每个字段可以被索引与搜索可以作数据库用;还是一个分布式实时分析搜索引擎,能胜任上百个服务节点的扩展,并支持PB级别(大数据级别)的结构化(定死的,进去多少出来多少,多余的全部抛弃)或者非结构化数据(只需要直到其属性即可);

1.1 衍生的开源软件

Elasticsearch :分布式搜索引擎Logstash:日志的采集与解析工具Kibana:可视化分析平台Beats:数据采集工具家族(替换Logstash)X-Pack:功能包

1.2 ES特性

速度快、易扩展、弹性、灵活、操作简单、多语言客户端分布式:横向扩展非常灵活全文检索:基于lucene的强大的全文检索能力;**近实时搜索和分析:**数据进入ES,可达到近实时搜索,还可进行聚合分析高可用:容错机制,自动发现新的或失败的节点,重组和重新平衡数据模式自由:ES的动态mapping机制可以自动检测数据的结构和类型,创建索引并使数据可搜索。RESTful API:JSON + HTTP

1.3 ES核心概念

Near Realtime(NRT) 近实时:数据提交索引后,立马就可以搜索到。

Cluster 集群:一个集群由一个唯一的名字标识,默认为“elasticsearch”。集群名称非常重要,具有相同集群名的节点才会组成一个集群。集群名称可以在配置文件中指定。

Node 节点:存储集群的数据,参与集群的索引和搜索功能。像集群有名字,节点也有自己的名称,默认在启动时会以一个随机的UUID的前七个字符作为节点的名字,你可以为其指定任意的名字。通过集群名在网络中发现同伴组成集群。一个节点也可是集群。

Index 索引:一个索引是一个文档的集合(等同于solr中的集合)。每个索引有唯一的名字,通过这个名字来操作它。一个集群中可以有任意多个索引。Type 类型:指在一个索引中,可以索引不同类型的文档,如用户数据、博客数据。从6.0.0 版本起已废弃,一个索引中只存放一类数据。

Document 文档:被索引的一条数据,索引的基本信息单元,以JSON格式来表示。

Shard 分片:在创建一个索引时可以指定分成多少个分片来存储。每个分片本身也是一个功能完善且独立的“索引”,可以被放置在集群的任意节点上。分片的好处:允许我们水平切分/扩展容量、可在多个分片上进行分布式的、并行的操作,提高系统的性能和吞吐量。

注意:分片数创建索引时指定,创建后不可改了。备份数可以随时改。

Replication 备份: 一个分片可以有多个备份(副本)。备份的好处:高可用。一个主分片挂了,副本分片就顶上去 扩展搜索的并发能力、吞吐量。搜索可以在所有的副本上并行运行。-高并发下副本也可搜索

1.4 结构化数据与非结构化数据

平时的数据可以分为结构化数据和非结构化数据:

结构化数据是指格式和长度固定的数据,如一个人的年龄,姓名等;非结构化数据是指格式和长度不固定的数据,如一个文章的内容等;

           对于结构化数据,可以存储在DB中通过精确匹配找到。但是对于非结构化数据,一般查询时只能提供查询的局部信息或模糊信息,传统数据库无法根据这些信息进行查询,效率差;

1.5 倒排索引

倒排索引是相对于正排索引而言的,可以有效的解决该问题;

正排索引可以通过id查找到对应的文章,但是无法通过给的部分内容如elasticsearch,找出含有该关键字的文档。

倒排索引会先对文档进行分析将其拆分成单个Term, 并存储包含该Term的文档id,这样便可以实现通过内容查找对应文档,如包含elasticsearch的文档为文档1;

倒排索引的过程:

通过倒排索引获得“搜索引擎”对应的文档id列表,有1和3;通过正排索引查询1和3的完整内容;返回最终结果;

2. ES的安装使用

2.1 安装

官网下载地址: https://www.elastic.co/downloads/elasticsearch

推荐到华为云镜像下载:https://mirrors.huaweicloud.com/

JDK版本: 1.8

2.2 启动

解压安装包,进入bin目录中双击elasticsearch.bat等待启动完毕;

打开浏览器,输入 http://localhost:9200 出现以下画面,说明ES安装成功;

2.3 ES端口

9300端口: ES节点之间通讯使用,9300是tcp通讯端口,集群间和TCPClient 都走它;9200端口: ES节点和外部通讯使用,9200是http协议的RESTful接口;

2.4 可视化工具Kibana

Kibana是一个针对Elasticsearch的开源分析及可视化平台,使用Kibana可以查询、查看并与存储在ES索引的数据进行交互操作,同时也能执行高级的数据分析,并能以图表、表格和地图的形式查看数据 ;

2.4.1 下载安装Kibana

下载安装包,需要和ES版本匹配,下载完毕后安装到相应的目录就行;

下载地址:https://www.elastic.co/downloads/kibana

2.4.2 配置

在目录config/kibana.yml中配置 elasticsearch.hosts: 的值为ES的访问地址;

2.4.3 启动Kibana

双击bin/kibana.bat

访问地址:http://localhost:5601

2.5 集成Ikanalyzer

IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包;从3.0版本开始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化;

2.5.1 下载安装Ikanalyzer

获取 ES-IKAnalyzer插件,需要和ES版本一致;

将ik的压缩包解压到 ES安装目录的plugins/目录下(新建文件夹analysis-ik),重启ES;

下载地址: https://github.com/medcl/elasticsearch-analysis-ik/releases

2.5.2 两种分词模式

Ik分词器有ik_max_word和ik_smart两种模式:

ik_max_word:会将文本做最细粒度的拆分;ik_smart:会做最粗粒度的拆分;

2.5.3 测试分词_细粒度拆分

{ "text":"我爱学习,最爱学Java", "analyzer":"ik_max_word" }

2.5.4 测试分词_粗粒度拆分

{ "text":"我爱学习,最爱学Java", "analyzer":"ik_smart" }

2.5.5 自定义分词库

首先在IKAnalyzer.cfg.xml里面定义自定义的字典,我这里是main.dic(自己随意命名);

<?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">main.dic</entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords"></entry> <!--用户可以在这里配置远程扩展字典 --> <!-- <entry key="remote_ext_dict">words_location</entry> --> <!--用户可以在这里配置远程扩展停止词字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>

3. 使用Kibana实现增删查改

3.1 创建索引

PUT /kak { "settings": { "index":{ "number_of_shards":5, "number_of_replicas":3 } } }

3.2 查看索引

#查看单个 GET /kak/_settings #查看所有 GET /_all/_settings 1234

3.3 添加文档

PUT /kak/student/1 { "name":"kaka", "sex":"man", "age":23, "score":100 } POST /kak/student/2 { "name":"taotao", "sex":"woman", "age":23, "score":100 }

3.4 查询文档

GET /kak/student/1 GET /kak/student/_search

3.5 修改文档

PUT方法:存在就修改,不存在就新增;

PUT /kak/student/1 { "name":"kaka", "sex":"man", "age":23, "score":150 }

3.6 删除文档

#删除单个 DELETE /kak/student/2 #删除全部 DELETE /kak

4. 批量获取文档信息

创建索引、添加文档

PUT kak_01 PUT kak_01/student/1 { "name":"kaka", "age":23, "sex":"man" } PUT kak_01/student/2 { "name":"zhuangzhuang", "age":23, "sex":"woman" } PUT kak_02 PUT kak_02/student/1 { "name":"zhangsan", "age":23, "sex":"man" } PUT kak_02/student/2 { "name":"lisi", "age":23, "sex":"woman" }

4.1 获取多个索引下面的多个文档对象

GET /_mget { "docs":[ { "_index": "kak_01", "_type": "student", "_id": 1 }, { "_index": "kak_01", "_type": "student", "_id": 2 } ] }

4.2 指定具体的字段

GET /_mget { "docs":[ { "_index":"kak_01", "_type":"student", "_id":1, "_source":["name","age"] }, { "_index":"kak_01", "_type":"student", "_id":2, "_source":["name","age","sex"] } ] }

4.3 简化批量获取的方式

GET /kak_01/student/_mget { "docs":[ { "_id":1 }, { <span class="token string">"_id"</span>:2 <span class="token punctuation">}</span> <span class="token punctuation">]</span>

}

5. 使用Bulk API实现批量操作

语法格式:

{action:{metadata}}

{requstbody}

action:(行为)

create:文档不存在时创建update:更新文档index:创建新文档或替换已有文档delete:删除一个文档

create 和index的区别:

如果数据存在,使用create操作失败,会提示文档已经存在;如果数据存在,使用index则可以成功执行;

5.1 批量添加

POST kak_01/student/_bulk {"index":{"_id":3}} {"name":"kak_03","age":23,"sex":"woman"} {"index":{"_id":4}} {"name":"kak_04","age":23,"sex":"woman"} {"index":{"_id":5}} {"name":"kak_05","age":23,"sex":"man"}

5.2 批量查询

GET kak_01/student/_mget { "ids":[1,2,3] }

5.3 批量删除

POST kak_01/student/_bulk {"delete":{"_index":"kak_01","_type":"student","_id":4}} {"delete":{"_index":"kak_01","_type":"student","_id":5}}

5.4 注意事项

操作的大小建议:

Bulk会把将要处理的数据载入内存中,所以数据量是有限制的,最佳的数据量不是一个确定的数值取决于硬件;

一般建议是1000-5000个文档,大小建议是5-15MB,默认不能超过100M,可以在ES的配置文件($ES_HOME下的config下的elasticsearch.yml)中设置;

6. 采用乐观锁机制实现并发控制

6.1 内部版本

         ElasticSearch采用了乐观锁来保证数据的一致性,当用户对document进行操作时,并不需要对该document作加锁和解锁的操作,只需要指定要操作的版本;当版本号一致时,ElasticSearch会允许该操作顺利执行,当版本号存在冲突时,ElasticSearch会提示冲突并抛出异常(VersionConflictEngineException异常);

ElasticSearch的版本号的取值范围为1到2^63-1。使用的是_version(每修改一个版本加一)

6.2 外部版本

         Elasticsearch在处理外部版本号时会与对内部版本号的处理有些不同。它不再是检查version是否与请求中指定的数值相同,而是检查当前的version是否比指定的数值小。如果请求成功,那么外部的版本号就会被存储到文档中的version中。为了保持version与外部版本控制的数据一致使用version_type=external ;

7. Mapping

查看自动生成的映射情况

GET kak_01/_mapping 1

核心数据类型:

字符型:string

string类型包括,text 和 keyword

text类型被用来索引长文本,在建立索引前会将这些文本进行分词,转化为词的组合,建立索引。允许es来检索这些词语。text类型不能用来排序和聚合。Keyword类型不需要进行分词,可以被用来检索过滤、排序和聚合。keyword 类型字段只能用本身来进行检索

数字型:long, integer, short, byte, double, float

日期型:date

布尔型:boolean

二进制型:binary

关键的属性:

“index”: true分词,false不分词,设置成false,字段将不会被索引;

“analyzer”:"ik"指定分词器,默认分词器为standard analyzer

PUT /lib { "settings":{ "number_of_shards" : 3, "number_of_replicas" : 0 }, "mappings":{ "properties":{ "title":{"type":"text"}, "name":{"type":"text","analyzer":"standard"}, "publish_date":{"type":"date","index":false}, "price":{"type":"double"} } } }

定义Mapping没有类型,之前能写进去是因为通过PUT,放文档放进去的;

8. 通用查询

8.1 准备数据

PUT /lib2 { "settings":{ "number_of_shards" : 3, "number_of_replicas" : 0 }, "mappings":{ "properties":{ "name": {"type":"text"}, "address": {"type":"text"}, "age": {"type":"integer"}, "interests": {"type":"text"}, "birthday": {"type":"date"} } } } PUT /lib2/_doc/1 { "name" : "kak", "address" : "sx", "age" : 32, "interests" : "java,music", "birthday": "1988-08-08" }

PUT /lib2/_doc/2 { “name” : “taotao”, “address” : “sz”, “age” : 33, “interests” : “java,music,money”, “birthday”: “1983-08-08” }

PUT /lib2/_doc/2 { “name” : “taotao”, “address” : “sz”, “age” : 33, “interests” : “java,music,money”, “birthday”: “1983-08-08” }

8.2 精确查找

term查询

8.2.1 查询某个字段里含有某个关键词的文档

GET /lib2/_search/ { "query": { "term": { "name": { "value": "kak" } } } }

8.2.2 查询某个字段里含有多个关键词的文档

GET /lib2/_search/ { "query": { "terms": { "interests": [ "java", "music" ] } } }

8.3 设值返回的条数

GET /lib2/_search { "from": 0, "size": 2, "query": { "terms": { "interests": [ "java", "music" ] } } }

8.4 设值返回的版本

GET /lib2/_search { "version": true, "from":0, "size": 2, "query": { "terms": { "interests": [ "java", "money" ] } } }

8.5 分词查找

match query知道分词器的存在,会对filed进行分词操作,然后再查询

GET /lib2/_search { "query": { "match": { "name": "kak helloworld" } } }

8.6 指定多个字段进行查询

GET /lib2/_search { "query": { "multi_match": { "query": "java", "fields": ["interests","name"] } } }

8.7 短语查询

ElasticSearch引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变

GET /lib2/_search { "query": { "match_phrase": { "interests": "java,music" } } }

8.8 指定返回的字段

GET /lib2/_search { "_source": ["address","name"], "query": { "match": { "interests": "java" } } }

8.9 排序

GET /lib2/_search { "query": { "match_all": {} }, "sort": [ { "age": { "order": "desc" } } ] }

8.10 前缀匹配

GET /lib2/_search { "query": { "match_phrase_prefix": { "name": { "query": "kak" } } } }

8.11 范围查询

GET /lib2/_search { "query": { "range": { "birthday": { "from": "1988-08-08", "to": "2020-08-08", "include_lower": true, "include_upper": false } } } }

8.12 通配符

允许使用通配符* 和 ?来进行查询:

*代表0个或多个字符?代表任意一个字符 GET /lib2/_search { "query": { "wildcard": { "name": "kak*" } } }

8.13 高亮查询

GET /lib2/_search { "query": { "match": { "interests": "java" } }, "highlight": { "fields": { "interests": {} } } }

9. Bool过滤查询

可以实现组合过滤查询must:必须满足的条件(and)should:可以满足也可以不满足的条件(or)must_not:不需要满足的条件(not ) GET /lib2/_search { "post_filter": { "bool": { "should":[ {"term":{"age":32}}, {"term":{"interests":"java"}} ], "must_not":{ "term":{"age":90} } } } }

GET /lib2/_search { "post_filter": { "bool": { "must":[ {"term":{"age":32}}, {"term":{"interests":"java"}} ] } } }

10. 范围查找

gt:>lt: <gte: >=lte: <= GET /lib2/_search { "post_filter": { "range": { "age": { "gte": 10, "lte": 32 } } } }

11. 聚合查询

11.1 求和

sum:求和

GET /lib2/_search { "size": 0, "aggs": { "agesum": { "sum": { "field": "age" } } } }

11.2 最小值

min:最小值

GET /lib2/_search { "size": 0, "aggs": { "agemin": { "min": { "field": "age" } } } }

11.3 最大值

max:最大值 GET /lib2/_search { "size": 0, "aggs": { "agemax": { "max": { "field": "age" } } } }

11.4 平均值

avg:平均值 GET /lib2/_search { "size": 0, "aggs": { "ageavg": { "avg": { "field": "age" } } } }

11.5 求基数

cardinality:基数(互不相同的值的个数 ) GET /lib2/_search { "size": 0, "aggs": { "agecardinality": { "cardinality": { "field": "age" } } } }

11.6 分组

terms:分组 GET /lib2/_search { "size": 0, "aggs": { "ageterms": { "terms": { "field": "age" } } } }

最新回复(0)