1.Elasticsearch(ES)介绍和安装
1.1为什么需要单独的搜索服务
- 用户访问我们的首页,一般都会直接搜索来寻找自己想要购买的商品。
- 而商品的数量非常多,而且分类繁杂。如何能正确的显示出用户想要的商品,并进行合理的过滤,尽快促成交易,是搜索系统要研究的核心。
- 面对这样复杂的搜索业务和数据量,使用传统数据库搜索就显得力不从心,一般我们都会使 用全文检索技术Elasticsearch。
1.2全文检索
全文检索:类似于百度、google等搜索引擎,输入一个内容,可以很快速的搜索出和内容相关的其他内容,速度快,性能高,查询范围大。
检索及搜索及查询
数据库查询
数据库查询其实就是使用select * from xxx 查询数据库数据。
数据库查询问题
问题1
问题2
通过上述的案例,我们知道使用数据库查询数据存在性能低、功能弱等问题,在大数据量的情况 下,这些问题将制约搜索操作,而这些问题可以使用倒排索引来解决这些问题,从而提高搜索效率。
倒排索引
例如:
静夜思
床前明月光,疑是地上霜。
举头望明月,低头思故乡。
水调歌头
明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。”
使用倒排索引操作
但是使用倒排索引,value的内容将会非常的多,所以可以对其进行优化,在value中存储内容的 唯一标识即可。
倒排索引:将各个文档中的内容,进行分词,形成词条。然后记录词条和数据的唯一标识(id) 的对应关系,形成的产物。
1.3Elasticsearch简介
Elasticsearch是一个基于Lucene的搜索服务器引擎(软件)。它提供了一个分布式多用户能力的全文搜索引擎(软件),基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache 许可条款下的开放源码发布,是一种流行的企业级搜索引擎(软件)。类似的还有solr。
Elastic有一条完整的产品线及解决方案:Elasticsearch、Kibana、Logstash等,前面说的三个就是大家常说的ELK(日志分析)技术栈。(现在称之为Elastic Stack:https://www.elastic.co/cn/el astic-stack/)
1.3.1Elasticsearch的特点
- 分布式,无需人工搭建集群(天生就是集群的)(solr就需要人为配置,使用Zookeeper作为注册中心)
- Restful风格,一切API都遵循Rest原则,容易上手
- 近实时搜索,数据更新在Elasticsearch中几乎是完全同步的。(但还是不同步的)
1.3.2应用场景
- 搜索:海量数据的查询
- 日志数据分析
- 实时数据分析
扩展:solr和Elasticsearch的区别:
-
es基本是开箱即用,非常简单。Solr安装略微复杂一丢丢
-
Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
-
Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。
-
Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
-
Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;
ES建立索引慢,即实时性查询快,用于facebook、新浪等搜索。
Solr 是传统搜索应用的有力解决方案,但Elasticsearch 更适用于新兴的实时搜索应用。
-
Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。
Elasticsearch和Mysql的分工:
Elasticsearch:主要负责大数据量的查操作。
Mysql:主要负责增、删、改、少量数据的查操作。
1.3.3 ElasticSearch数据的存储和搜索原理
数据存储原理
搜索原理
1.4Elasticsearch的安装和配置
- Elasticsearch的版本我们使用7.4.0
- 需要Linux中的JDK11及以上
1.4.1 elasticsearch默认不允许以root账号运行(启动)
elasticsearch默认不允许以root账号运行,所以我们使用Linux的另一个账号zhangsan操作(也可以自己创建新的账号进行操作)
useradd zhangsan
passwd zhangsan
1.4.2 上传安装包,并解压
- cd /opt
- mkdir elasticsearch
- 将资料中的elasticsearch-7.4.0-linux-x86_64.tar.gz上传到Linux系统中
- cd /
- chown -R zhangsan:zhangsan /opt/elasticsearch #将/opt/elasticsearch目录的操作权限设置给zhangsan
- cd /opt/elasticsearch
- tar -zxvf elasticsearch-7.4.0-linux-x86_64.tar.gz
- mv elasticsearch-7.4.0 elasticsearch
- cd elasticsearch /config
- vim jvm.options 修改成如下内容
-Xms128m
-Xmx128m
- vim elasticsearch.yml 修改如下内容
path.data: /opt/elasticsearch/data # 数据目录位置
path.logs: /opt/elasticsearch/logs # 日志目录位置
network.host: 0.0.0.0 # 此行前面带一个空格 绑定到0.0.0.0,允许任何ip来访问
http.port: 9200
cluster.name: elasticsearch
node.name: node-1
cluster.initial_master_nodes: ["node-1"]
进入/opt/elasticsearch目录创建以下两个目录
- cd /opt/elasticsearch
- mkdir data
- mkdir logs
1.4.3运行
启动之前需要解决启动的两个问题.
- 启动错误1解决
以上错误表示elasticsearch7.4.0需要JDK11才能运行,但是我们之前配置的环境是JDK8,如 何调整呢?
1.修改elasticsearch安装目录下的bin目录下的elasticsearch-env脚本文件,将第38行左右 的内容
if [ ! -z "$JAVA_HOME" ]; then
JAVA="$JAVA_HOME/bin/java"
else
if [ "$(uname -s)" = "Darwin" ]; then
# OSX has a different structure
JAVA="$ES_HOME/jdk/Contents/Home/bin/java"
else
JAVA="$ES_HOME/jdk/bin/java"
fi
fi
注释掉,往下添加以下内容
if [ "$(uname -s)" = "Darwin" ]; then
# macOS has a different structure
JAVA="$ES_HOME/jdk.app/Contents/Home/bin/java"
else
JAVA="$ES_HOME/jdk/bin/java"
fi
JAVA_TYPE="bundled jdk"
2.修改elasticsearch安装目录下的config目录下的jvm.options,将第35行左右的内容
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
注释掉,往下添加以下内容
-XX:+UseG1GC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
- 启动错误2解决
我们用的是zhangsan用户,而不是root,所以文件权限不足。
我们用root用户登录修改配置文件。
su root
vim /etc/security/limits.conf 在文档最后添加如下内容:
* soft nofile 65536
* hard nofile 131072
* soft nproc 4096
* hard nproc 4096
vim /etc/sysctl.conf 在文档最后添加如下内容:
vm.max_map_count=655360
sysctl -p
- chown -R zhangsan:zhangsan/opt/elasticsearch #将/opt/elasticsearch目录的操作权限设置给zhangsan
- su zhangsan
- cd /opt/elasticsearch/elasticsearch/bin/
- ./elasticsearch 如下图启动成功 9300:集群节点间通讯接口 9200:客户端访问接口
如果想后台运行启动
./elasticsearch -d
之后通过ps -ef | grep elasticsearch查看
-
防火墙将9200、9300端口放行(此操作需要切换到root用户)
su root firewall-cmd --permanent --add-port=9200/tcp firewall-cmd --permanent --add-port=9300/tcp systemctl restart firewalld
-
在浏览进行测试,出现如下内容表示成功(192.168.200.129:9200)
number" : "7.4.0" 表示elasticsearch版本
lucene_version" : "8.2.0" 表示lucene版本
name : 默认启动的时候指定了 ES 实例名称
cluster_name : 默认名为 elasticsearch
1.5安装kibana
1.5.1 什么是kibana
Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在
Elasticsearch索引中的数据。使用Kibana,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表板
(dashboard)实时显示Elasticsearch查询动态。Kibana还是一个基于Node.js的Elasticsearch索引库数据统计工具,可以利用
Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。而且还提供了操作Elasticsearch索引数据的控制台,并且提供了一定的API提示,非常有利
于我们学习Elasticsearch的语法。
1.5.2 安装kibana
- cd /opt
- mkdir kibana
- 将课程资料中的kibana-7.4.0-linux-x86_64.tar.gz上传到Linux中
- tar -zxvf kibana-7.4.0-linux-x86_64.tar.gz
1.5.3 修改kibana.yml配置文件
-
cd /opt/kibana/kibana-7.4.0-linux-x86_64/config
-
vim kibana.yml
server.port: 5601 server.host: "0.0.0.0" server.name: "kibana-test" elasticsearch.hosts: ["http://192.168.200.129:9200"] elasticsearch.requestTimeout: 99999
server.port:http访问端口
server.host:ip地址,0.0.0.0表示可远程访问
server.name:kibana服务名
elasticsearch.hosts:elasticsearch地址
elasticsearch.requestTimeout:请求elasticsearch超时时间,默认为30000,此处可根据情况设置。
1.5.4 启动测试
Linux防火墙放开端口
firewall-cmd --permanent --add-port=5601/tcp
systemctl restart firewalld
由于kibana不建议使用root用户启动,如果用root启动,需要加--allow-root参数。
cd /opt/kibana/kibana-7.4.0-linux-x86_64/bin/
# 启动
./kibana --allow-root
启动成功。
看到这个界面,说明Kibanan已成功安装。
Discover :可视化查询分析器
Visualize :统计分析图表
Dashboard :自定义主面板(添加图表)
Dev Tools :Console控制台(同CURL/POSTER,操作ES代码工具,代码提示,很方便) Management :管理索引库(index)、已保存的搜索和可视化结果(save objects)、设置 kibana 服 务器属性。
1.6安装ik分词器
IK分词器是适用于中文环境的一个分词器
Elasticsearche默认分词器效果一个字一个字的拆分,不利于中国汉字多字组合查询:
我是中国人 -> 我 是 中 国 人
IK分词器的效果,可以分出一个一个的词,利于中文汉字多次查询:
我是中国人 -> 我 是 中 国 中国 人 国人 中国人
1.6.1 上传ik压缩文件
将资料中的elasticsearch-analysis-ik-7.4.0.zip上传到Linux 的/opt/elasticsearch/elasticsearch/plugins目录中
1.6.2 解压文件
- unzip elasticsearch-analysis-ik-7.4.0.zip -d ik-analyzer
- 把压缩文件删除掉,否则启动失败
1.6.3 重启es
1.6.4 测试分词器的作用
1.默认分词器standard的效果
POST _analyze
{
"analyzer": "standard",
"text": "我是中国人"
}
2.使用中文分词器ik_max_word
POST _analyze
{
"analyzer": "ik_max_word",
"text": "我是中国人"
}
2.ElasticSearch的语法学习
2.1基本概念
- 集群中的一些概念
索引集(Indices,index的复数):逻辑上的完整索引 collection1
分片(shard):数据拆分后的各个部分
副本(replica):每个分片的复制
Elasticsearch本身就是分布式的,因此即便你只有一个节点,Elasticsearch默认也会对 你的数据进行分片和副本操作,当你向集群添加新数据时,数据也会在新加入的节点中进行 平衡。
2.2索引的操作
2.2.1 创建索引
settings:索引库的设置
- number_of_shards:分片数量,7.x版本之前默认5,7.x版本之后默认1
- number_of_replicas:副本数量,7.x版本之前默认1,7.x版本之后默认1
2.2.2 查看索引
2.2.3 删除索引
2.3 映射配置
2.3.1 什么是映射
- 映射是定义文档的过程,文档包含哪些字段,这些字段是否保存,是否索引,是否分词等
- 只有配置清楚映射关系,Elasticsearch才会帮我们进行索引库的创建
2.3.2 创建映射字段的语法格式
需要先构建索引库,在构建索引库中的映射关系
PUT /索引库名/_mapping/类型名称?include_type_name=true
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
}
}
}
- 类型名称:就是前面讲解的type的概念,类似于数据库中的不同表 字段名:任意填写。Elasticsearch7.0之后不支持类名名称写法所以需要添加 include_type_name=true参数进行支持设置。
- type:类型,可以是text、long、short、date、integer、object等
- index:是否可以使用索引查询,默认为true
- store:是否额外存储,默认为false
- analyzer:分词器,这里的 ik_max_word 即使用ik分词器
PUT lanou/_mapping/goods?include_type_name=true
{
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"images": {
"type": "keyword",
"index": "false"
},
"price": {
"type": "float"
}
}
}
2.3.3 查看映射关系
GET /test/_mapping
GET test/_mapping/goods?include_type_name=true 都可以
2.3.4 字段常用属性详解
1.type属性
-
String类型,又分两种:
- text:可分词,不可参与聚合
- keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合
-
Numerical:数值类型,分两类
- 基本数据类型:long、interger、short、byte、double、float、half_float
- 浮点数的高精度类型:scaled_float
- 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后 存储,取出时再还原。
-
Date:日期类型
elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long, 节省空间。
2.index
- true:字段会被索引,则可以用来进行搜索。默认值就是true
- false:字段不会被索引,不能用来搜索
但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为 false。
3.store
- Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做 _source 的属性中。而且我们可以通过过滤 _source 来选择哪些要显示,哪些不显示。
- 而如果设置store为true,就会在 _source 以外额外存储一份数据,多余,因此一般我们都 会将store设置为false,事实上,store的默认值就是false。
2.4新增数据
2.4.1 随机生成id
POST /索引库名/映射类型名
{
"key":"value"
}
POST /test/goods/
{
"title":"小米手机",
"images":"http://image.lano.com/12479122.jpg",
"price":2699.00
}
- 响应结果
{
"_index": "test",
"_type": "goods",
"_id": "NuiUwHgBQgWzr9qXHSmk",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
- 查询数据
GET test/_search
{
"query": {
"match_all": {}
}
}
//也可以按照下面方式查询
GET test/goods/_search
{
"query":{
"match_all":{}
}
}
2.4.2自定义id
POST /索引库名/映射类型名/id值
{
...
}
POST /test/goods/2
{
"title":"大米手机",
"images":"http://image.test.com/11111.jpg",
"price":289.00
}
- 相应数据
{
"_index": "test",
"_type": "goods",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
2.4.3智能判断
POST /test/goods/3
{
"title":"超米手机",
"images":"http://image.test.com/12479122.jpg",
"price":2899.00,
"stock": 200,//没有这个字段的映射定义
"saleable":true//没有这个字段的映射定义
}
- 查看结果
- 查看索引
2.5修改数据
把刚才新增的请求方式改为PUT,就是修改了。不过修改必须指定id。
- id对应文档存在,则删除之后新增
- id对应文档不存在,则新增
PUT /test/goods/3
{
"title":"超大米手机",
"images":"http://image.test.com/12479122.jpg",
"price":3899.00,
"stock": 100,
"saleable":true
}
2.6删除数据
- 语法格式
DELETE /索引库名/映射类型名/id值
DELETE /test/goods/3