ElasticSearch
1.什么是ElasticSearch
Elasticsearch是用Java语言开发的基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
2.为什么实用ElashSearch?
1).ElashSearch扩展性好:分布式,无需人工搭建集群(solr就需要人为配置,使用Zookeeper作为注册中心)。
2).ElashSearch近实时的去索引数据、搜索数据。
3.ElashSearch的原理?
下图是ElasticSearch的索引结构,右边黑蓝色色部分是原始文档,左边黄色部分是逻辑结构,逻辑结构也是为了更好的去描述ElasticSearch的工作原理及去使用物理结构中的索引文件。
3.1 索引
3.1.1 倒排索引(Inverted
index):也常被称为反向索引,倒排索引是从关键字到文档的映射(已知关键字求文档)。
1)、将搜索的文档最终以Document方式存储起来。(如下图Doc_1,Doc_2)
2)、将要搜索的文档内容分词,所有不重复的词组成分词列表。(如下图Term)
3)、每个词和docment都有关联。
现在,如果我们想搜索 包含quick brown词条的文档:
两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单 相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳。
3.2 RESTful应用方法
Elasticsearch提供 RESTful Api接口进行索引、搜索,并且支持多种客户端。
下图是es在项目中的应用方式:
1)用户在前端搜索关键字
2)项目前端通过http方式请求项目服务端
3)项目服务端通过Http RESTful方式请求ES集群进行搜索
4)ES集群从索引库检索数据。
4 .ElasticSearch 安装
4.1 Windows安装ElasticSearch
4.1.1 安装条件:
1)、jdk必须是jdk1.8.0_131以上版本。
2)、支持tar、zip、rpm等多种安装方式。
3)在windows下开发建议使用ZIP安装方式。
4.1.2下载 ES:
ElasticSearch官网:https://www.elastic.co/cn/
4.1.3 ES是Java开发的应用,解压即安装:
tar -zxvf elasticsearch-6.2.3.tar.gz
4.1.4 ES目录结构
bin 目录:可执行文件包
config 目录:配置相关目录
lib 目录:ES 需要依赖的 jar 包,ES 自开发的 jar 包
modules 目录:功能模块的存放目录,如aggs、reindex、geoip、xpack、eval
plugins 目录:插件目录包,三方插件或自主开发插件
logs 目录:日志文件相关目录
data 目录:在 ES 启动后,会自动创建的目录,内部保存 ES 运行过程中需要保存的数据。
4.1.5 配置文件
ES安装目录config中配置文件如下:
elasticsearch.yml:用于配置Elasticsearch运行参数
jvm.options:用于配置Elasticsearch JVM设置
log4j2.properties:用于配置Elasticsearch日志
4.1.5.1 elasticsearch.yml
cluster.name: sxt
node.name: sxt_node_1
network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts:
["0.0.0.0:9300", "0.0.0.0:9301"]
discovery.zen.minimum_master_nodes: 1
bootstrap.memory_lock: false
path.data: D:\ElasticSearch-1\data
path.logs: D:\ElasticSearch-1\logs
http.cors.enabled: true
http.cors.allow-origin:/.*/
常用的配置项如下:
cluster.name:
配置elasticsearch的集群名称,默认是elasticsearch。建议修改成一个有意义的名称。
node.name:
节点名,通常一台物理服务器就是一个节点,es会默认随机指定一个名字,建议指定一个有意义的名称,方便管理
一个或多个节点组成一个cluster集群,集群是一个逻辑的概念,节点是物理概念,后边章节会详细介绍。
path.data:
设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开。
path.logs:
设置日志文件的存储路径,默认是es根目录下的logs文件夹
bootstrap.memory_lock: true
设置为true可以锁住ES使用的内存,避免内存与swap分区交换数据。
network.host:
设置绑定主机的ip地址,设置为0.0.0.0表示绑定任何ip,允许外网访问,生产环境建议设置为具体的ip。
http.port: 9200
设置对外服务的http端口,默认为9200。
transport.tcp.port: 9300
集群结点之间通信端口
node.master:
指定该节点是否有资格被选举成为master结点,默认是true,如果原来的master宕机会重新选举新的master。
node.data:
指定该节点是否存储索引数据,默认为true。
discovery.zen.ping.unicast.hosts:
[“host1:port”, “host2:port”, “…”]
设置集群中master节点的初始列表。
discovery.zen.ping.timeout: 3s
设置ES自动发现节点连接超时的时间,默认为3秒,如果网络延迟高可设置大些。
discovery.zen.minimum_master_nodes:
主结点数量的最少值 ,此值的公式为:(master_eligible_nodes / 2)+ 1 ,比如:有3个符合要求的主结点,那么这里要设置为2。
node.max_local_storage_nodes:
单机允许的最大存储结点数,通常单机启动一个结点建议设置为1,开发环境如果单机启动多个节点可设置大于1.
4.1.5.2 jvm.options
设置最小及最大的JVM堆内存大小:
在jvm.options中设置 -Xms和-Xmx:
1)两个值设置为相等
2)将Xmx 设置为不超过物理内存的一半。
4.1.5.3 properties
日志文件设置,ES使用log4j,注意日志级别的配置。
4.1.6 启动
进入bin目录,在cmd下运行:elasticsearch.bat
4.1.7 测试:
ES 中,只要启动了任意一个 ES 应用,就是启动了一个 ES 的 cluster 集群。默认的 ES集群命名为 elasticsearch。如果启动了多个应用(可以在多个节点或单一节点上启动多个应用),默认的 ES 会自动找集群做加入集群的过程。
浏览器访问:http://127.0.0.1:9200
显示结果:
4.2 head插件安装
head插件是ES的一个可视化管理插件,用来监视ES的状态,并通过head客户端和ES服务进行交互,比如创建映射、创建索引等, 从ES6.0开始,head插件支持使得node.js运行。
1)head插件下载:下载地址: https://github.com/mobz/elasticsearch-head
2) 安装
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install
npm -v
3) 测试
浏览器访问:http://127.0.0.1:9100/、
若打开浏览器调试工具发现报错: Originnull is not allowed by Access-Control-Allow-Origin.
原因是:head插件作为客户端要连接ES服务(localhost:9200),此时存在跨域问题,elasticsearch默认不允许跨域访问。
解决方案:
在config/elasticsearch.yml后面增加以下参数:
#开启cors跨域访问支持,默认为false
http.cors.enabled: true
#跨域访问允许的域名地址,(允许所有域名)以上使用正则
http.cors.allow-origin: /.*/
4.3安装Kibana
Kibana是ES提供的一个基于 WEB 的管理控制台, 可以很容易实现高级的数据分析和可视化,以图标的形式展现出来。
kibana可以用来编辑请求语句的,方便学习操作es的语法。有时在进行编写程序,写到查询语句时,往往我会使用kibana进行书写,然后再粘贴到程序中。(不容易出错)
4.3.1 下载
ElasticSearch官网:https://www.elastic.co/cn/
4.3.2 安装
在window中安装Kibana很方便,解压即安装
4.3.3 修改配置
vim config/kibana.yml
把以下注释放开,使配置起作用:
server.port:5601
server.host:"0.0.0.0" #允许来自远程用户的连接
elasticsearch.url:http://127.0.0.1:9200# Elasticsearch实例的URL
kibana.index:".kibana"#如果没有索引,Kibana 会创建一个新的索引来存储保存的检索,可视化控件以及仪表板
4.3.4 启动
双击bin目录下 kibana.bat
4.3.5 测试
5. Elasticsearch相关操作
5.1 index库管理
5.1.1 创建index库
number_of_shards - 是表示一个索引库将拆分成多片分别存储不同的结点,提高了ES的处理能力和高可用性
number_of_replicas- 是为每个 primary shard分配的replica shard数,如果只有一台机器,设置为0
效果:
5.1.2 修改index
注意:索引一旦创建,primary shard 数量不可变化,可以改变replica shard 数量。
ES 中对 shard 的分布是有要求的,有其内置的特殊算法:
1、ES 尽可能保证 primary shard平均分布在多个节点上;
2、Replica shard 会保证不和他的那个 primary shard 分配在同一个节点上;
如过只有一个节点,则此案例执行后索引的状态一定是yellow。
5.1.3删除index
5.1.4 为什么primary shard数量不可变
原因:假如我们的集群在初始化的时候有5个primaryshard,我们往里边加入一个document id=5,假如hash(5)=23,这时该document 将被加入 (shard=23%5=3)P3这个分片上。如果随后我们给es集群添加一个primaryshard ,此时就有6个primary shard,当我们GET id=5 ,这条数据的时候,es会计算该请求的路由信息找到存储他的 primary shard(shard=23%6=5) ,根据计算结果定位到P5分片上。而我们的数据在P3上。所以es集群无法添加primary shard,但是可以扩展replicas shard。
5.2mapping管理
映射,创建映射就是向索引库中创建field(类型、是否索引、是否存储等特性)的过程,下边是document和field与关系数据库的概念的类比: 索引库(indices)--------------------------------Databases数据库 类型(type)-----------------------------Table数据表 文档(Document)----------------Row 行 字段(Field)-------------------Columns 列注意:6.0之前的版本有type(类型)概念,type相当于关系数据库的表,ES6.x 版本之后,type概念被弱化ES官方将 在ES7.0版本中彻底删除type。
5.2.1 创建mapping
5.2.2 查询mappin
5.2.3 删除mapping
通过删除索引来删除映射。
5.3 document管理
ES中的文档相当于MySQL数据库表中的记录。
5.3.1 PUT语法
语法:PUT /index_name/type_name/id{field_name:field_value}
结果:
"_index": "test_index",新增的 document 在什么 index 中,
"_type": "my_type",新增的 document 在 index 中的哪一个 type 中。
"_id": "1",指定的 id 是多少
"_version": 1, document的版本是多少,版本从 1 开始递增,每次写操作都会+1
"result": "created",本次操作的结果,created 创建,updated 修改,deleted 删除
"_shards": {分片信息
"total": 2,分片数量只提示primary shard
"successful": 1,数据 document 一定只存放在 index 中的某一个 primary shard 中
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
5.3.2 POST语法
此操作为ES 自动生成 id 的新增 Document 方式。
语法:POST /index_name/type_name{fieldname:fieldvalue}
5..4 查询document
语法:
GET/index_name/type_name/id
或
GET/index_name/type_name/_search?q=field_name:field_value
查询结果:
{
"took": 1, #执行的时长。单位毫秒
"timed_out": false, #是否超时
"_shards": { # shard相关数据
"total": 2, #总计多少个shard
"successful": 2, # 成功返回结果的 shard 数量
"skipped": 0,
"failed": 0
},
"hits": { #搜索结果相关数据
"total": 3, # 总计多少数据,符合搜索条件的数据数量
"max_score": 1, # 最大相关度分数,和搜索条件的匹配度
"hits": [#具体的搜索结果
{
"_index": "java17",#索引名称
"_type": "course", #类型名称
"_id": "1",# id值
"_score": 1, #匹配度分数,本条数据匹配度分数
"_source": { #具体的数据内容
"name": "php从入门到放弃",
"description": "php是世界上最好的语言",
"studymodel": "201001"
}
}
]
}
}
5.4 删除Document
6 ES读写原理
documnet routing(数据路由)
当客户端创建document的时候,es需要确定这个document放在该index哪个shard上,这个过程就是document routing。
路由过程:
路由算法:shard = hash(routing) %number_of_primary_shards
routing:document的_id,可能是手动指定,也可能是自动生成,决定一个document在哪个shard上
number_of_primary_shards:主分片。
6.1ES document写操作原理
ES增删改的处理流程:增删改的请求一定作用在主分片上。
假如我们es集群有3个node,每个node上一个主分片一个复制分片,
如下图:
1)、第一步 客户端发起一个PUT请求,假如该请求被发送到第一个node节点,那么该节点将成为协调节点(coordinating
node),如图P1所在的节点就是协调节点。他将根据该请求的路由信息计算,该document将被存储到哪个分片。
2)、第二步通过计算发现该document被存储到p0分片,那么就将请求转发到node2节点。
3)、第三步P0根据请求信息创建document,和相应的索引信息,创建完毕后将信息同步到自己的副本节点R0上。
4)、第四步P0和R0将通知我们的协调节点,任务完成情况。
5)、第五部协调节点响应客户端最终的处理结果。
6.2 读操作原理
假如我们es集群有3个node,每个node上一个主分片一个复制分片,
如下图:
1)、第一步客户端发送读器请求到协调节点(coordinate node)。
2)、第二步协调节点(coordinate node)根据请求信息对document进行路由计算,将请求转发到对应的node,node2或者node3,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica(副本)中随机选择一个让读请求负载均衡。
3)、第三步相应接收到请求的节点(node2或者node3)将处理结果返回给协调节点(coordinate node)。
4)、第四步协调节点将最终的结果反馈给客户端。
7. IK分词器
在添加文档时会进行分词,索引中存放的就是一个一个的词(term),当你去搜索时就是拿关键字去匹配词,最终找到词关联的文档。
普通分词器:
会发现分词的效果将“测试”这个词拆分成两个单字“测”和“试”,这是因为当前索引库使用的分词器对中文就是单字分词。
7.1. 安装IK分词器
使用IK分词器可以实现对中文分词的效果。下载IK分词器:(Github地址:https://github.com/medcl/elasticsearch-analysis-ik)
解压,并将解压的文件拷贝到ES安装目录的plugins下的ik(重命名)目录下
7.2.两种分词模式
ik分词器有两种分词模式:ik_max_word和ik_smart模式。
1、ik_max_word
会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。
2、ik_smart
会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。
7.3自定义词库
如果要让分词器支持一些专有词语,可以自定义词库。
iK分词器自带一个main.dic的文件,此文件为扩展词典。
也可以上边的目录中新建一个my.dic文件(注意文件格式为utf-8(不要选择utf-8 BOM))
可以在其中自定义词汇:
比如定义:
配置文件中配置my.dic,
7.4 field详细介绍
7.4.1 field的属性介绍
type: 通过type属性指定field的类型。
analyzer:通过analyzer属性指定分词模式。
指定了analyzer是指在索引和搜索都使用ik_max_word,如果单独想定义搜索时使用的分词器则可以通过
search_analyzer属性。
对于ik分词器建议是索引时使用ik_max_word将搜索内容进行细粒度分词,搜索时使用ik_smart提高搜索精确性。
index:通过index属性指定是否索引。
默认为index=true,即要进行索引,只有进行索引才可以从索引库搜索到。
但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将index设置
为false。 删除索引,重新创建映射,将pic的index设置为false,尝试根据pic去搜索,结果搜索不到数据
store:是否在source之外存储,每个文档索引后会在 ES中保存一份原始文档,存放在"_source"中,一般情况下不需要设置
store为true,因为在_source中已经有一份原始文档了。
field索引不存储\
如果某个字段内容非常多,业务里面只需要能对该字段进行搜索,最后返回文档id,查看文档内容会再次到mysql或者hbase中取数据,把大字段的内容存在Elasticsearch中只会增大索引,这一点文档数量越大结果越明显,如果一条文档节省几KB,放大到亿万级的量结果也是非常可观的。
如果只想存储某几个字段的原始值到Elasticsearch,可以通过incudes参数来设置,在mapping中的设置如下:
同样,可以通过excludes参数排除某些字段:
7.5常用field类型
text文本字段
keyword关键字字段
keyword字段为关键字字段,通常搜索keyword是按照整体搜索,所以创建keyword字段的索引时是不进行分词的
date日期类型
日期类型不用设置分词器,通常日期类型的字段用于排序。
1)format
通过format设置日期格式,多个格式使用双竖线||分隔, 每个格式都会被依次尝试, 直到找到匹配的
Numeric类型
下图是ES支持的数值类型:
1、尽可能选择范围小的数据类型, 字段的长度越短, 索引和搜索的效率越高;
2、对于浮点数尽量用比例因子,比如一个价格字段,单位为元,我们将比例因子设置为100这在ES中会按分存
储,映射如下:
由于比例因子为100,如果我们输入的价格是23.45则ES中会将23.45乘以100存储在ES中。
使用比例因子的好处是整型比浮点型更易压缩,节省磁盘空间。
8 Spring Boot整合ElasticSearch
ES提供多种不同的客户端:
1、TransportClient
ES提供的传统客户端,官方计划8.0版本删除此客户端。
2、RestClient
RestClient是官方推荐使用的,它包括两种:Java Low Level REST
Client和 Java High
Level REST Client。
ES在6.0之后提供 Java
High Level REST Client,两种客户端官方更推荐使用 Java High Level REST
Client,不过当前它还处于完善中,有些功能还没有。
本教程准备采用 Java High Level REST Client,如果它有不支持的功能,则使用Java Low Level REST Client
8.1创建项目
8.2 修改pom.xml文件
8.3 修改application.yml
8.4 创建RestHighLevelClient配置类
8.5 创建启动类
8.6 测试
8.6.1 创建索引库
kinbana:api
java代码:
8.6.2 删除索引库
kinbana:api
java代码:
8.6.3 添加文档
kinbana:api
java代码:
8.6.4 批量添加文档
kinbana:api
java代码:
8.6.5 修改文档:
kinbana:api
java代码:
8.8.6. 删除文档
kinbana:api
java代码:
8.6.7 文档搜索:
8.6.7.1 简单搜索
kibana:api
java代码:
8.6.7.2 DSL搜索( match_all查询)
DSL(Domain Specific Language)是ES提出的基于json的搜索方式,在搜索时传入特定的json格式的数据来完成不同的搜索需求,DSL比URI搜索方式功能强大,在项目中建议使用DSL方式来完成搜索。
kinbana:api
8.6.7.3 DSL搜索( Term 查询 )
Term Query为精确查询,在搜索时会整体匹配关键字,不再将关键字分词。
kinbana:api
java代码:
8.6.7.4 DSL搜索( match查询 )
match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。
query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用逗号分隔也可以不用。
operator:or 表示只要有一个词在文档中出现则就符合条件,and表示每个词都在文档中出现则才符合条件。
kinbana:api
java代码:
8.6.7.5 DSL搜索( multi_match查询 )
termQuery和matchQuery是在一个field中去匹配,multiQuery是拿关键字去多个Field中匹配。
匹配多个字段时可以提升字段的boost(权重)来提高得分, 如“name^10”表示权重提升10倍,执行查询时name中包括spring关键字的文档排在前边。
kinbana:api
java代码:
8.6.7.6 DSL搜索( bool查询 )
布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来。
参数:
must:表示必须,多个查询条件必须都满足。(通常使用must)
should:表示或者,多个查询条件只要有一个满足即可。
must_not:表示非。
kinbana:api:
java代码:
8.6.7.7 DSL搜索(filter查询)
此操作实际上就是query DSL 的补充语法。过滤的时候,不进行任何的匹配分数计算,相对于 query 来说,filter 相对效率较高。Query 要计算搜索匹配相关度分数。Query更加适合复杂的条件搜索。查询:
kinbana:api
java代码:
8.7 highlight查询
高亮显示。高亮不是搜索条件,是显示逻辑,在搜索的时候,经常需要对条件实现高亮显示。
kinbana:api
java代码:
9.集群管理
9.1集群结构
9.2 集群的三个角色
主节点:master节点主要用于集群的管理及索引比如新增节点、分片分配、索引的新增和删除等。
数据节点:data 节点上保存了数据分片,它负责索引和搜索操作。
客户端节点:client节点仅作为负载均衡器不存数据,只是将请求均衡转发到其它节点。
通过下边两项参数来配置节点的功能:
node.master: #是否允许为主节点
node.data: #允许存储数据作为数据节点
node.ingest: #是否允许成为协调节点,
四种组合方式:
master=true,data=true:即是主节点又是数据节点
master=false,data=true:仅是数据节点
master=true,data=false:仅是主节点,不存储数据
master=false,data=false:即不是主节点也不是数据节点,此时可设置ingest为true(默认)表示它是一个客户端。
9.3 创建结点2
3、修改elasticsearch-2的elasticsearch.yml内容如下:
cluster.name: sxt
node.name:sxt_node_2
network.host: 0.0.0.0
http.port:9201
transport.tcp.port:9301
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["0.0.0.0:9300", "0.0.0.0:9301"]
discovery.zen.minimum_master_nodes: 1
bootstrap.memory_lock: false
node.max_local_storage_nodes: 3
path.data: D:\ElasticSearch-2\data
path.logs: D:\ElasticSearch-2\logs
http.cors.enabled: true
http.cors.allow-origin: /.*/
9.4查看集群健康状态
GET _cluster/health
结果: