elasticsearch的学习
本文档的编写时根据腾讯云服务器centos7 和 es6.x版本进行编写
注意:es安装部分还没更新。。。。有问题可以留言。是根据6.x来的7.x的安装我会另外写一篇博文。。
因为第一次学习,教程中用的时es6,然后我自己都是用最新的,发现,最新的和视频教程中,很大区别,包括安装和处理报错信息,安装部分是我根据es7.x的截图,发现到后面错误解决不了,为了赶时间,学习,我又跟随视频中用es6.8来,所以这个文档,安装部分是es7.x的截图,理论知识并无太大区别。。这两天,在学习微信小程序,后面。再更新一下这个博文
一、什么是lucene?
Lucene是免费开源用于全文检索的程序工具包(API),由Apache软件基金会支持和提供。目前主流的java搜索框架都是依赖Lucene,官网:http://lucene.apache.org
我们为什么不直接使用它呢?Lucene底层的api调用起来非常复杂,代码的编写量会大大增加,因为es基于它封装和优化,使用起来就简单非常多。
二、搜索介绍
如果有了解过sphinx的就是一样的东西都是用来搜索数据,高亮数据等。
1、数据库搜索产生的问题
todo 画图
2、什么是全文检索?
全文检索是利用倒排索引技术对需要搜索的数据进行处理,然后提供快速匹配的技术。
其实全文检索还有另外一种专业定义,先创建索引然后对索引进行搜索的过程,就是全文检索。
(1)、倒排索引的理解?
倒排索引是一种存储数据的方式,与传统查找有很大区别
传统查找方式:采用数据按行存储,查找时逐行扫描,或者根据索引查找,然后匹配搜索条件,效率较差。概括来讲是先找到文档,然后看是否匹配。
倒排索引:首先对数据按列拆分存储,然后对文档中的数据分词,对词条进行索引,并记录词条在文档中出现的位置。这样查找时只要找到了词条,就找到了对应的文档。概括来讲是先找到词条,然后看看哪些文档包含这些词条。
(2)、创建倒排索引的流程
(1)、创建文档列表
首先将数据按列进行拆分存储,类型于mysql的表存储,每一条数据,就是一个文档,形成文档列表
(2)、创建倒排索引列表
然后对文档中的数据进行分词,得到词条。对词条进行编号,并以词条创建索引。然后记录下包含该词条的所有文档编号(及其它信息)。
(3)、倒排索引的搜索过程
用图来理解
(4)、全文检索应用场景
1.当数据库搜索不能满足我们的业务需求的时候,比如海量数据搜索
2.需要进行相关度排序,高亮显示等操作
三、分词器
Analyzer(分词器)的作用是把一段文本中的词按规则取出所包含的所有词。对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由子类实现的,所以对于不同的语言(规则),要用不同的分词器
注意:在创建索引时会用到分词器,在使用字符串搜索时也会用到分词器,这两个地方要使用同一个分词器,否则可能会搜索不出结果。所以当改变分词器的时候,需要重新建立索引库
1、常见的中文分词器
中文的分词比较复杂,因为不是一个字就是一个词,而且一个词在另外一个地方就可能不是一个词,如在“帽子和服装”中,“和服”就不是一个词。对于中文分词,通常有三种方式:单字分词、二分法分词、词典分词
(1)、单字分词
就是按照中文一个字一个字地进行分词,效率比较低。如:“我们是中国人”,效果:“我”、“们”、“是”、“中”、“国”、“人”。(StandardAnalyzer就是这样),es默认就是单字分词
(2)、二分法分词
按两个字进行切分,把相邻的两个字组成词分解出来,效率也比较低。而且很多情况下分的词不对。如:“我们是中国人”,效果:“我们”、“们是”、“是中”、“中国”、“国人”。(CJKAnalyzer就是这样)
(3)、词库分词(IKAnalyzer)
按某种算法构造词,然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语。通常词库分词被认为是最理想的中文分词算法。如:“我们是中国人”,效果为:“我们”、“中国人”。(使用极易分词的MMAnalyzer。可以使用“极易分词”,或者是“庖丁分词”分词器、IKAnalyzer)。
四、什么是Elasticsearch
Elasticsearch官网
https://www.elastic.co/cn/products/elasticsearch
Elaticsearch简称为es,是一个开源的可扩展的全文检索引擎服务器,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。es使用Java开发并使用Lucene作为其核心来实现索引和搜索的功能,但是它通过简单的RestfulAPI和javaAPI来隐藏Lucene的复杂性,从而让全文搜索变得简单。
五、Elasticsearch的安装(需要修改)
环境准备:centos7 ,
注意:如果是es7.0以上是不需要安装jdk8了的。
我这里是安装的最新的es7.9,如果你是低版本则需要按照jdk8以及以上,最新版请忽略
jdk8(=jdk1.8)安装
#查找
yum search java|grep jdk
#下载
yum install java-1.8.0-openjdk.x86_64
(1)、新建用户
出于安全考虑,elasticsearch默认不允许以root账号运行
#增加用户
useradd elastic
#passwd+用户名 用这条命令激活并更改密码用户才可用
passwd elastic
因为学习阶段,我设置密码为root
,你们可以自行设置,一般像腾讯云服务器默认密码都很复杂,因为重装镜像的时候设置太简单无法重装,设置太简单会有如下提示
切换用户
su - elastic
(2)下载软件,并上传,解压
https://www.elastic.co/cn/downloads/elasticsearch
上传压缩包到 usr/local/src/
,我个人的习惯是所有的源码包统统在这个文件夹进行统一管理
解压
注意:这个步骤因为你此时是elatisc
用户所有直接解压到 usr/local/src/
是没有权限的,需要解压到自己的家目录
tar -zxvf elasticsearch-7.9.1-linux-x86_64.tar.gz -C /home/elastic/
#改一下啊目录的名称
mv /home/elastic/elasticsearch-7.9.1/ /home/elastic/elasticsearch
查看目录结构
名称 | 解释 |
---|---|
bin | 二进制脚本,包含启动命令等 |
config | 配置文件目录 |
jdk | 自带jdk |
lib | 依赖包目录 |
logs | 日志文件目录 |
modules | 模块库 |
plugins | 插件目录(IK分词器插件) |
data | 数据储存目录(暂时没有,需要在配置文件中指定存放位置,启动es时会自动根据指定位置创建) |
此时的plugins
是空的
(3)修改配置
修改jvm配置,注意如果太小的同样也启动不
-Xms512m
-Xmx512m
打开 elasticsearch.yml
文件修改下面这几个配置。
data 和logs的目录
path.data: /home/elastic/elasticsearch/data
#
# Path to log files:
#
#path.logs: /path/to/logs
path.logs: /home/elastic/elasticsearch/logs
允许所有的域名访问
#network.host: 192.168.0.1
network.host: 0.0.0.0
(4)解决启动报错
切换到bin
目录下,直接启动,会报错
./Elasticsearch
#启动方式二:后台启动
./elasticsearch -d
问题一:
max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
elasticsearch用户拥有的最大虚拟内存太小,至少需要262144;
解决办法
注意这个配置文件 是在 /etc 下面 。不要去安装目录找
vim /etc/sysctl.conf
G 跳转到文件末尾 添加
vm.max_map_count=262144
保存退出后,立即执行
sysctl -p
问题二:
the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
默认发现设置不适合生产使用;至少有一个[discovery.seed\u主机, discovery.seed_提供程序, cluster.initial_master_节点]必须配置
解决办法:
切换到安装目录
vim config/elasticsearch.yml
将 #cluster.initial_master_nodes: [“node-1”, “node-2”] 修改为 cluster.initial_master_nodes: [“node-1”]
然后启动es,终于大功告成
直接访问 ip:9200
有的同学到达这一步,还是访问不了,会出现如下情况
如果此时 还是访问不了。需要关闭一下防火墙,如果是云服务器需要配置一下安装组规则
查看防火墙:
firewall-cmd --state (centos7)
关闭防火墙:
systemctl stop firewalld.service (centos7)
禁止开机启动防火墙:
systemctl disable firewalld.service (centos7)
六、kibana
默认端口5601
它是elasticsearch的图形化界面工具,和下面类似
mysql HeidiSQL、Navcat、PhpMyadmin
redis RedisDesktopManager
memcached memadmin
1、下载,直接到下载页面
https://www.elastic.co/cn/downloads/kibana
2、上传
3、解压
4、修改配置
进入kibana目录修改配置文件
vim /config/kibana.yml
#server.host: "localhost"
server.host: "0.0.0.0"
#修改语言包 默认是en
i18n.locale: "zh-CN"
5、启动kibana
./bin/kibana
访问你的ip地址:5601
ctrl+i
自动缩进
ctrl+回车
执行语句
七、IK分词集成
Lucene的IK分词器早在2012年已经没有维护了,现在我们要使用的是在其基础上维护升级的版本,并且开发为Elasticsearch的集成插件了,与Elasticsearch一起维护升级,版本也保持一致,所以下载时一定要下载对应的版本
https://github.com/medcl/elasticsearch-analysis-ik
1、安装
方式一:使用插件安装
在elasticsearch的bin目录下执行以下命令,es插件管理器会自动帮我们安装,然后等待安装完成就行了
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.8.0/elasticsearch-analysis-ik-6.8.0.zip
下载完成后会提示 Continue with installation?输入 y 即可完成安装
方式二:上传安装包安装(推荐)
在elasticsearch/plugins
目录下创建analysis-ik
目录
mkdir analysis-ik
复制到该目录然后解压
cp /usr/local/src/elasticsearch-analysis-ik-6.8.0.zip /home/elastic/elasticsearch/plugins/analysis-ik
重启es 和kibana即可成功集成IK分词
2、分词模式
IK分词器有两种分词模式:ik_max_word
和ik_smart
模式。
(1)、ik_max_word (常用)
会将文本做最细粒度的拆分
ik_max_word 测试,前面分词器有讲到analyzer是一个抽象类。
POST _analyze
{
"analyzer": "ik_max_word",
"text": "新华社长江前线"
}
输出结果
(2)、ik_smart
会做最粗粒度的拆分
ik_smart测试:
POST _analyze
{
"analyzer": "ik_smart",
"text": "新华社长江前线"
}
执行结果
问题引申:如果江前线是一个人名我们该匹配出来呢?答:添加拓展词
3、添加扩展词典和停用词典
(1)、停用词
有些词在文本中出现的频率非常高,但对本文的语义产生不了多大的影响,比如的、呢、啊、了这些词。
停用词经常被过滤掉,不会被进行索引。
停用词可以加快索引的速度,减少索引库文件的大小。
(2)、扩展词
就是不想让哪些词被分开,让他们分成一个词。比如上面的江前线
(3)、自定义扩展词库操作
1.进入到 elasticsearch/config/analysis-ik/(插件安装方式) 或 elasticsearch/plugins/analysis-ik/config(安装包安装方式) 目录下, 新增自定义词典
vim myext_dict.dic
输入 :江前线
2.将我们自定义的扩展词典文件添加到IKAnalyzer.cfg.xml
配置中
vim IKAnalyzer.cfg.xml
3.然后重启es和kibana后再次测试
八、API的学习
Elasticsearch提供了Rest风格的API,即http请求接口,而且也提供了各种语言的客户端API
1、Rest风格的API
文档地址
https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
2、客户端API
Elasticsearch支持的客户端非常多
https://www.elastic.co/guide/en/elasticsearch/client/index.html
九、ElasticSearch相关概念
Elasticsearch是基于Lucene的全文检索库,本质也是存储数据,很多概念与MySQL类似的。注意:es7.x版本中,已经移除了type概念
对比关系
索引库(indexes)---------------------------------Databases 数据库
类型(type)----------------------------------Table 数据表
文档(Document)--------------------------Row 行
字段(Field)---------------------Columns 列
映射配置(mappings)--------- 表结构
概念 | 说明 |
---|---|
索引库(indexes) | 索引库包含一堆相关业务,结构相似的文档document数据,比如说建立一个商品product索引库,里面可能就存放了所有的商品数据。 |
类型(type) | type是索引库中的一个逻辑数据分类,一个type下的document,都有相同的field,类似于数据库中的表。比如商品type,里面存放了所有的商品document数据。6.0版本以后一个index只能有1个type,6.0版本以前每个index里可以是一个或多个type。 |
文档(document) | 文档是es中的存入索引库最小数据单元,一个document可以是一条客户数据,一条商品数据,一条订单数据,通常用JSON数据结构表示。document存在索引库下的type类型中。 |
字段(field) | Field是Elasticsearch的最小单位。一个document里面有多个field,每个field就是一个数据字段 |
映射配置(mappings) | 类型对文档结构的约束叫做映射(mapping),用来定义document的每个字段的约束。如:字段的数据类型、是否分词、是否索引、是否存储等特性。类型是模拟mysql中的table概念。表是有结构的,也就是表中每个字段都有约束信息; |
十、索引库的操作
1、创建索引库
语法
PUT /blog1
{
"settings": {
"属性名": "属性值"
}
}
settings:就是索引库设置,其中可以定义索引库的各种属性,目前我们可以不设置,都走默认
1、查看索引库
语法:
GET /blog1
3、删除索引库
语法
DELETE /blog1
再次查看,返回索引不存在
十一、类型及映射操作
数据表和表结构的操作
有了索引库,等于有了数据库中的database。接下来就需要索引库中的类型了,也就是数据库中的表。创建数据库表需要设置字段约束,索引库也一样,在创建索引库的类型(等于创建表)时,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做字段映射(mapping)
字段的约束包括但不限于:
字段的数据类型
是否要存储
是否要索引
是否分词
分词器是什么
1.创建映射字段(需先创建索引库)
语法:
PUT /索引库名/_mapping/类型名称 或 索引库名/类型名称/_mapping
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
}
}
}
类型名称:就是前面讲的type的概念,类似于数据库中的表
字段名:任意填写,下面指定许多属性,例如:
type:类型,可以是text、long、short、date、integer、object等
index:是否索引,默认为true
store:是否存储,默认为false
analyzer:分词器,这里的ik_max_word即使用ik分词器
先创建一个空的索引库 shop
执行结果
2.映射属性详解
(1)type
Elasticsearch中支持的数据类型非常丰富
String类型,又分两种
text:可分词,不可参与聚合
keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合
Numerical:数值类型,分两类
基本数据类型:long、interger、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
(需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。)
Date:日期类型
elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。
Array:数组类型
进行匹配时,任意一个元素满足,都认为满足
排序时,如果升序则用数组中的最小值来排序,如果降序则用数组中的最大值来排序
Object:对象
{
name:"Jack",
age:21,
girl:{
name: "Rose", age:21
}
}
如果存储到索引库的是对象类型,例如上面的girl,会把girl变成两个字段:girl.name和girl.age
(2)index
index影响字段的索引情况。
true:字段会被索引,则可以用来进行搜索。默认值就是true
false:字段不会被索引,不能用来搜索
index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。
但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为false。
(3)store
是否将数据进行独立存储。
原始的文本会存储在_source里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source里面提取出来的。当然你也可以独立的存储某个字段,只要设置store:true即可,获取独立存储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置,默认为false。
3.查看映射关系
语法
GET /索引库名/_mapping/类型名
示例:
GET /shop/_mapping/goods
执行结果
{
"shop" : {
"mappings" : {
"goods" : {
"properties" : {
"images" : {
"type" : "keyword",
"index" : false
},
"price" : {
"type" : "float"
},
"subtitle" : {
"type" : "text",
"analyzer" : "ik_max_word"
},
"title" : {
"type" : "text",
"analyzer" : "ik_max_word"
}
}
}
}
}
}
4.一次创建索引库和类型(常用)
刚才 的案例中我们是把创建索引库和类型分开来做,其实也可以在创建索引库的同时,直接制定索引库中的类型
基本语法
put /索引库名
{
"settings":{
"索引库属性名":"索引库属性值"
},
"mappings":{
"类型名":{
"properties":{
"字段名":{
"映射属性名":"映射属性值"
}
}
}
}
}
示例:
PUT /shop
{
"settings": {},
"mappings": {
"goods": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"subtitle": {
"type": "text",
"analyzer": "ik_max_word"
},
"images": {
"type": "keyword",
"index": "false"
},
"price": {
"type": "float"
}
}
}
}
}
执行结果
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "shop"
}
十二、文档操作(Row 行)
文档,即索引库中某个类型下的数据,会根据规则创建索引,将来用来搜索。可以类比做数据库中的每一行数据。
1、新增文档
(1)不指定ID,随机生成
语法:
POST /索引库名/类型名
{
"key":"value"
}
示例:
POST /shop/goods/
{
"title":"小米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":2699.00
}
(1)自己指定ID
语法:
POST /索引库名/类型/id值
{
...
}
示例:
POST /shop/goods/1
{
"title":"小米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":2699.00
}
1、查看文档
语法:
GET /shop/goods/默认随机生成的id
GET /shop/goods/或者自己指定的id
2、修改文档
id对应文档存在,则修改
id对应文档不存在,则新增
把刚才新增的请求方式改为PUT,就是修改,不过修改必须指定id
比如我们新增一条id为3的数据,不存在,则应该是新增
PUT /shop/goods/3
{
"title":"超米手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":3899.00
}
我们修改数据后再次执行
3、删除文档
(1)根据ID删除
语法:
DELETE /索引库名/类型名/id值
示例:
DELETE /shop/goods/1
(2)根据查询条件删除(post)
语法:
POST /索引库名/_delete_by_query
{
"query": {
"match": {
"字段名": "搜索关键字"
}
}
}
示例
POST /shop/_delete_by_query
{
"query": {
"match": {
"title": "小米"
}
}
}
(3)删除所有数据
语法:
POST /索引库名/_delete_by_query
{
"query": {
"match_all": {}
}
}
示例:
POST /shop/_delete_by_query
{
"query": {
"match_all": {}
}
}
十三、查询操作(重点)
准备学习测试数据,_bulk
批量操作接口
POST /shop/goods/_bulk
{"index":{}}
{"title":"大米手机","images":"http://image.leyou.com/12479122.jpg","price":3288}
{"index":{}}
{"title":"小米手机","images":"http://image.leyou.com/12479122.jpg","price":2699}
{"index":{}}
{"title":"小米电视4A","images":"http://image.leyou.com/12479122.jpg","price":4288}
1、基本查询
语法:
POST /索引库名/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}
这里的query代表一个查询对象,里面可以有不同的查询属性
查询类型
例如:match_all, match,term , range 等等
查询条件:查询条件会根据类型的不同,写法也有差异,后面详细讲解
(1)、查询所有(match_all)
示例:
POST /shop/_search
{
"query": {
"match_all": {}
}
}
执行结果
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "shop",
"_type" : "goods",
"_id" : "FVhZn3QBDwlWNzf7FI0_",
"_score" : 1.0,
"_source" : {
"title" : "小米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 2699
}
},
{
"_index" : "shop",
"_type" : "goods",
"_id" : "FlhZn3QBDwlWNzf7FI0_",
"_score" : 1.0,
"_source" : {
"title" : "小米电视4A",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 4288
}
},
{
"_index" : "shop",
"_type" : "goods",
"_id" : "FFhZn3QBDwlWNzf7FI0_",
"_score" : 1.0,
"_source" : {
"title" : "大米手机",
"images" : "http://image.leyou.com/12479122.jpg",
"price" : 3288
}
}
]
}
}
解释说明
took:查询花费时间,单位是毫秒
time_out:是否超时
_shards:分片信息
hits:搜索结果总览对象
total:搜索到的总条数
max_score:所有结果中文档得分的最高分
hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
_index:索引库
_type:文档类型
_id:文档id
_score:文档得分
_source:文档的源数据
(2)、匹配查询(match)
会把查询条件进行分词,然后根据词条关系进行查询
词条关系有
1.or关系(默认)
POST /shop/_search
{
"query": {"match": {
"title": "小米电视"
}}
}
不仅会查询到电视,而且与小米相关的都会查询到,多个词之间是or的关系
2.and关系
某些情况下,我们需要更精确查找,我们希望这个关系变成and,可以这样做:
POST /shop/_search
{"query": {"match": {
"title": {"query": "小米电视4A","operator": "and"}
}}}
3.match和match_all查询结果中的max_score为什么不一样?
具体说明一下 max_score 是怎么回事?
因为创建索引库的时候我们指定了分词ik_max_word
在进行查询的操作的时候会先分词,那么也就是说查询的结果越接近分出来的词得分越高,比如
你搜索 小米电视 那么 小米手机 小米电视4A 这两条数据 则是小米手机的更高,原因是因为没有小米电视这个词 因为小米电视被拆分成小米和电视
match_all 则是 查询所有,所以分值都一样都是 1
(3)、多字段查询(multi_match)
multi_match与match类似,不同的是它可以在多个字段中查询
为了测试效果我们在这里新增一条数据:
POST /shop/goods
{
"title": "华为手机",
"images": "http://image.leyou.com/12479122.jpg",
"price": 5288,
"subtitle": "小米"
}
示例:
POST /shop/_search
{
"query": {
"multi_match": {
"query": "小米",
"fields": ["title","subtitle"]
}
}
}
执行结果:
只要所查询的字段中包含小米的商品都会被查询出来
(4)、 词条匹配(term)
term 查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字符串
示例
查询出价格是2699的商品
POST /shop/_search
{
"query":{
"term":{
"price":2699
}
}
}
#或者这种写法都可以
POST /shop/_search
{
"query": {
"term": {
"price": {
"value": "2699"
}
}
}
}
执行结果
(5)、 多词条精准匹配(terms)
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,类似于mysql的in
示例
查询价格是2699和5288的
POST /shop/_search
{
"query":{
"terms":{
"price":[2699,5288]
}
}
}
执行结果
2、结果过滤
默认情况下,elasticsearch在搜索的结果中,会把文档中保存在_source的所有字段都返回。
如果我们只想获取其中的部分字段,我们可以添加_source的过滤
(1)、直接指定字段
示例:
只获取title和price字段
POST /heima/_search
{
"_source": ["title","price"],
"query": {
"term": {
"price": 2699
}
}
}
执行结果
(2)、指定includes和excludes
includes:来指定想要显示的字段
excludes:来指定不想要显示的字段
示例:
POST /shop/_search
{
"_source": {
"includes":["title","price"]
},
"query": {
"term": {
"price": 2699
}
}
}
POST /shop/_search
{
"_source": {
"excludes": ["images"]
},
"query": {
"term": {
"price": 2699
}
}
}
两个结果都是一样的
3、高级查询
(1)、布尔组合(bool)
bool把各种其它查询通过must(与)、must_not(非)、should(或)的方式进行组合
示例代码
GET /shop/_search
{
"query":{
"bool":{
"must": { "match": { "title": "小米" }},
"must_not": { "match": { "title": "电视" }},
"should": { "match": { "title": "手机" }}
}
}
}
翻译一下:必须存在小米,一定不要电视,可以携带手机
执行结果
(2)、范围查询(range)
range 查询找出那些落在指定区间内的数字或者时间
操作符 | 说明 |
---|---|
gt | 大于 |
gte | 大于等于 |
lt | 小于 |
lte | 小于等于 |
示例
POST /shop/_search
{
"query":{
"range": {
"price": {
"gte": 3000,
"lt": 5000
}
}
}
}
(2)、模糊查询(fuzzy)
我们新增一个商品
POST /shop/goods/4
{
"title":"apple手机",
"images":"http://image.leyou.com/12479122.jpg",
"price":5899.00
}
它允许用户搜索词条与实际词条出现偏差,但是偏差的编辑距离不得超过2
POST /shop/_search
{
"query": {
"fuzzy": {
"title": "appla"
}
}
}
上面的查询,也能查询到apple手机
fuzziness
,你的搜索文本最多可以纠正几个字母去跟你的数据进行匹配,默认如果不设置,就是2
注意:下面这个apeee
也是可以匹配到的,因为ape
是三个能匹配到的,最大只能错两个,所以剩余两个ee
在容错范围内,如果是apeeee
则匹配不到结果
POST /shop/_search
{
"query": {
"fuzzy": {
"title": {
"value": "apeee",
"fuzziness": 2
}
}
}
}
4、排序
sort
可以让我们按照不同的字段进行排序,并且通过order
指定排序的方式
(1)、单字段排序
示例代码
POST /shop/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": {
"order": "asc"
}
}
]
}
(2)、 多字段排序
和msyql一样可以设置多个排序字段
假定我们想要结合使用 price和 _score(得分) 进行查询,并且匹配的结果首先按照价格排序,然后按照相关性得分排序
POST /shop/_search
{
"query":{
"match": {
"title": "小米"
}
},
"sort": [
{ "price": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
}
5、高亮
和sphinx高亮原理是一样的,在使用match查询的同时,加上一个highlight属性
POST /shop/_search
{
"query": {
"match": {
"title": "电视"
}
},
"highlight": {
"pre_tags": "<font color='pink'>",
"post_tags": "</font>",
"fields": {
"title": {}
}
}
}
解释说明
pre_tags:前置标签
post_tags:后置标签
fields:需要高亮的字段
title:这里声明title字段需要高亮,后面可以为这个字段设置特有配置,也可以空
6、分页
elasticsearch中实现分页的语法非常简单,一般是和排序在一起使用
POST /shop/_search
{
"query": {
"match_all": {}
},
"size": 2,
"from": 0
}
size:每页显示多少条
from:当前页起始索引, int start = (pageNum - 1) * size;
十四、Elasticsearch集群
1、单点的问题
单台服务器,往往都有最大的负载能力,超过这个阈值,服务器性能就会大大降低甚至不可用。单点的elasticsearch也是一样,那单点的es服务器存在哪些可能出现的问题呢?
单台机器存储容量有限
单服务器容易出现单点故障,无法实现高可用
单服务的并发处理能力有限
所以,为了应对这些问题,我们需要对elasticsearch搭建集群
2、数据分片
首先,我们面临的第一个问题就是数据量太大,单点存储量有限的问题。
大家觉得应该如何解决?
没错,我们可以把数据拆分成多份,每一份存储到不同机器节点(node),从而实现减少每个节点数据量
3、数据备份
数据分片解决了海量数据存储的问题,但是如果出现单点故障,那么分片数据就不再完整,这又该如何解决呢?
没错,就像大家为了备份手机数据,会额外存储一份到移动硬盘一样。我们可以给每个分片数据进行备份,存储到其它节点,防止数据丢失,这就是数据备份,也叫数据副本(replica)。
数据备份可以保证高可用,但是每个分片备份一份,所需要的节点数量就会翻一倍,成本实在是太高了!
为了在高可用和成本间寻求平衡,我们可以这样做:
首先对数据分片,存储到不同节点
然后对每个分片进行备份,放到对方节点,完成互相备份
这样可以大大减少所需要的服务节点数量,如图,我们以3分片,每个分片备份一份为例:
在这个集群中,如果出现单节点故障,并不会导致数据缺失,所以保证了集群的高可用,同时也减少了节点中数据存储量。并且因为是多个节点存储数据,因此用户请求也会分发到不同服务器,并发能力也得到了一定的提升。
4、搭建集群
集群需要多台机器,我们这里用一台机器来模拟,因此我们需要在一台虚拟机中部署多个elasticsearch节点,每个elasticsearch的端口都必须不一样
node-01:http端口9201,TCP端口9301
node-02:http端口9202,TCP端口9302
node-03:http端口9203,TCP端口9303
接下来的所有操作,记得要使用elastic用户来操作,
注意这里是在一台服务器中模拟伪集群
(1)目录改名
把原来的elasticsearch目录改名为elasticsearch-01
mv elasticsearch/ elasticsearch-01/
(2)删除原有生成的测试数据
rm -rf elasticsearch-01/data/nodes/
(3)修改一下配置
vim config/elasticsearch.yml
#集群名称
cluster.name: es-stu
#节点名称
node.name: node-1
#数据和日志的目录
path.data: /home/elastic/elasticsearch-01/data
path.logs: /home/elastic/elasticsearch-01/logs
#默认的端口9200注释打开 改成9201
http.port: 9201
#这个配置文件是没有的,自己添加上去
transport.tcp.port: 9301
#集群中其它节点的ip及端口
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9301", "127.0.0.1:9302","127.0.0.1:9303"]
#注释打开,配置2,意思是假如总共3台挂了一台只剩下2台的时候也提供服务
discovery.zen.minimum_master_nodes: 2
(4)复制剩余两台es服务器
直接把elasticsearch-01复制成elasticsearch-02 elasticsearch-03即可
cp -r elasticsearch-01/ elasticsearch-02/
cp -r elasticsearch-01/ elasticsearch-03/
3台就已经准备完毕
(5)修改剩余两台es服务器的配置
第三台道理相同
(6)修改kibana的配置
默认是连接的9200,现在已经端口被我改成了9201 9202 92013,所以需要改一下
#打开注释,可以是数组,连接一台就可以了
elasticsearch.hosts: ["http://localhost:9201"]
(7)分别启动三个节点
我复制了三个会话
(8)通过head插件连接查看集群
(9)测试集群中创建索引库
如何测试es服务集群是一个高可用的?
PUT /shop
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
number_of_shards:分片数量,这里设置为3
number_of_replicas:副本数量,这里设置为1,每个分片一个备份,一个原始数据,共2份。
head查看,我们可以查看到分片的存储结构
此时,我们把节点3的那台服务器给停掉,则节点一的0分片会自动变成主分片
(10)通过kibana查看集群
先启动kibana
启动kibana后刷新head插件发现多了很多个,就是上面文档有那么多的原因
十五、完结
基本的东西将完了,至于各个客户端操作大家自己根据文档,进行学习。我是学习php的,有的可能是java python 等等
如果是php的同学请移步我的另外一篇博客