
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。
全文搜索引擎
根据关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回
RESTFUL
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。
RESTFUL特点包括:
1、每一个URI代表1种资源;
2、客户端使用GET、POST、PUT、DELETe4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3、通过操作资源的表现形式来操作资源;
4、资源的表现形式是XML或者HTML;
5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
JSON 语法规则
JSON 语法是 Javascript 对象表示语法的子集。
数据在名称/值对中
数据由逗号分隔
大括号 {} 保存对象
中括号 [] 保存数组,数组可以包含多个对象
JSON 数据的书写格式是:
key : value
{
"name":"张三","age":18
}
JSON数组
{
"students":[
{"name":"张三","age":18},
{"name":"李四","age":20},
{"name":"王五","age":22}
]
}
正排索引(传统)
| id | content |
|---|---|
| 1001 | my name is zhang san |
| 1002 | my name is li si |
倒排索引
| keyword | id |
|---|---|
| name | 1001, 1002 |
| zhang | 1001 |
Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。
Index(索引)
类比MySQL,Index相当于数据库。
动词,相当于 MySQL 中的 insert;
名词,相当于 MySQL 中的 Database
Type(类型)
类比MySQL,Type相当于数据表。
在 Index(索引)中,可以定义一个或多个类型。
类似于 MySQL 中的 Table;每一种类型的数据放在一起;
document(文档)
类比MySQL,document相当于数据。
保存在某个索引(Index)下,某种类型(Type)的一个数据(document),文档是 JSON 格式的,document 就像是 MySQL 中的某个 Table 里面的内容;
2、docker安装ElasticSearch1、拉取镜像
docker pull elasticsearch:7.8.0
2、创建文件
mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "http.host: 0.0.0.0">>/mydata/elasticsearch/config/elasticsearch.yml
3、提升文件权限
chmod -R 777 /mydata/elasticsearch/
4、启动容器
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx128m" -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:7.8.0
参数说明
--name elasticsearch:将容器命名为 elasticsearch -p 9200:9200:将容器的9200端口映射到宿主机9200端口 -p 9300:9300:将容器的9300端口映射到宿主机9300端口,目的是集群互相通信 -e "discovery.type=single-node":单例模式 -e ES_JAVA_OPTS="-Xms64m -Xmx128m":配置内存大小 -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:将配置文件挂载到宿主机 -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data:将数据文件夹挂载到宿主机 -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins:将插件目录挂载到宿主机(需重启) -d elasticsearch:7.7.0:后台运行容器,并返回容器ID
5、阿里云开启9200,9300daunkou
6、测试
47.108.170.87:9200 返回结果 name "e9c6802b4542" cluster_name "elasticsearch" cluster_uuid "dWtRimy5SA-S-co2fOBkcA" version number "7.8.0" build_flavor "default" build_type "docker" build_hash "757314695644ea9a1dc2fecd26d1a43856725e65" build_date "2020-06-14T19:35:50.234439Z" build_snapshot false lucene_version "8.5.1" minimum_wire_compatibility_version "6.8.0" minimum_index_compatibility_version "6.0.0-beta1" tagline "You Know, for Search"
7、docker容器自启动
docker update elasticsearch --restart=always3、docker安装Kibana
Kibana是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。Kibana与Elasticsearch的交互方式是各种不同的图表、表格、地图等,直观的展示数据,从而达到高级的数据分析与可视化的目的。
Elasticsearch、Logstash和Kibana这三个技术就是我们常说的ELK技术栈,可以说这三个技术的组合是大数据领域中一个很巧妙的设计。一种很典型的MVC思想,模型持久层,视图层和控制层。Logstash担任控制层的角色,负责搜集和过滤数据。Elasticsearch担任数据持久层的角色,负责储存数据。而我们这章的主题Kibana担任视图层角色,拥有各种维度的查询和分析,并使用图形化的界面展示存放在Elasticsearch中的数据。
3.1 docker 拉取kibana镜像,与Elasticsearch版本一致
docker pull kibana:7.8.0
3.2启动容器
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://47.108.170.87:9200 -p 5601:5601 -d kibana:7.8.0
3.3测试
http://47.108.170.87:5601
谷歌浏览器安装postman插件
火狐浏览器安装RESTClient和 HttpRequester 插件
二、CRUDget一般是获取,put创建,delete删除,
基本了解
_cat/nodes 查看所有节点
_cat/master 查看住节点
_cat/health 查看es健康状态
_cat/indices 查看所有索引 (相当于查看数据库里面的所有数据库)
put请求保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识
数据库 test 库,student表,1是主键
es:/test/student/1
test是索引==数据库
student 是类型 == 数据表
POST 新增。如果不指定 id,会自动生成 id。指定 id 就会修改这个数据,并新增版本号
PUT 可以新增可以修改。PUT 必须指定 id;由于 PUT 需要指定 id,我们一般都用来做修改操作,不指定 id 会报错。
post可以获得某类型下的所有数据/test/student
get必须加上id获得数据/test/student/1
post提交修改数据/test/student/2/_update
body为新数据
{
"doc":{
"id": 31,
"name": "何迪5201314",
"age": 20
}
}
delete请求删除数据/test/student/1
删除
index是test
type是student
id是_upJJXwBXMdUiOLkZ2Sk
批量bulk
POST test/studnet/_bulk
{"index":{"_id":"1"}}
{ "id": 1,
"name": "王一辉",
"age":18
}
{"index":{"_id":"2"}}
{ "id": 2,
"name": "何迪",
"age":18
}
1、创建索引
http://47.108.170.87:9200/shopping #put sent
返回结果
{
"acknowledged": true, //响应结果
"shards_acknowledged": true, //分片结果
"index": "shopping" //索引名称
}
再次发送报错
{
"error": {
"root_cause": [
{
"type": "resource_already_exists_exception",
"reason": "index [shopping/uRoeuSIBSb2ntHSkg37gMw] already exists",
"index_uuid": "uRoeuSIBSb2ntHSkg37gMw",
"index": "shopping"
}
],
"type": "resource_already_exists_exception",
"reason": "index [shopping/uRoeuSIBSb2ntHSkg37gMw] already exists",
"index_uuid": "uRoeuSIBSb2ntHSkg37gMw",
"index": "shopping"
},
"status": 400
}
2、查看所有索引
http://47.108.170.87:9200/_cat/indices //get sent
返回结果
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open shopping uRoeuSIBSb2ntHSkg37gMw 1 1 0 0 208b 208b
_cat查看;indices所有索引
相当于MySQL的show tables;
表头 含义
health 当前服务器健康状态: green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
status 索引打开、关闭状态
index 索引名
uuid 索引统一编号
pri 主分片数量
rep 副本数量
docs.count 可用文档数量
docs.deleted 文档删除状态(逻辑删除)
store.size 主分片和副分片整体占空间大小
pri.store.size 主分片占空间大小
http://47.108.170.87:9200/shopping //get sent
返回结果
{
"shopping": { //索引名
"aliases": {}, //别名
"mappings": {}, //映射
"settings": { //设置
"index": { //设置索引
"creation_date": "1627440132306", //索引-创建时间
"number_of_shards": "1", //索引-分片
"number_of_replicas": "1", //索引-分片
"uuid": "uRoeuSIBSb2ntHSkg37gMw", //索引-id
"version": {
"created": "7080099"
},
"provided_name": "shopping" //索引-名字
}
}
}
}
4、删除索引
http://47.108.170.87:9200/shopping #delete sent
返回结果
{
"acknowledged": true
}
5、创建文档
文档是建立在索引下面的
http://47.108.170.87:9200/shopping/_doc //POST Sent
body内容
{
"title":"小米手机",
"category":"小米",
"images":"http://www.gulixueyuan.com/xm.jpg",
"price":3999.00
}
返回结果
{
"_index": "shopping",
"_type": "_doc",
"_id": "bYMi63oBSIJIs80cgCJH",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
6、查询文档全部
http://47.108.170.87:9200/shopping/_doc/1 //GET Sent
返回结果
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 4,
"_seq_no": 4,
"_primary_term": 1,
"found": true,
"_source": {
"title": "小米机",
"category": "小米",
"images": "http://www.gulixueyuan.com/xm.jpg",
"price": 3999
}
}s
7、查询某个索引下的全部数据
http://47.108.170.87:9200/shopping/_search //GET Sent
注意:
要把上次创建body里面的内容删除了
8、全量修改
http://47.108.170.87:9200/shopping/_doc/1 //POST Sent
body内容:
{
"title":"华为手机",
"category":"华为",
"images":"http://www.gulixueyuan.com/hw.jpg",
"price":1999.00
}
返回结果:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 5,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 1
}
7、局部修改
http://47.108.170.87:9200/shopping/_update/1 //Post Sent
body内容:
{
"doc": {
"title":"苹果手机",
"category":"苹果"
}
}
返回结果
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 6,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 6,
"_primary_term": 1
}
8、删除
http://47.108.170.87:9200/shopping/_doc/1 //DELETE Sent
返回结果
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 7,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 7,
"_primary_term": 1
}
9、条件查询
url带参
http://47.108.170.87:9200/shopping/_search?q=category:红 //GET Sent
category包含红的
请求体
http://47.108.170.87:9200/shopping/_search //GET Sent
{
"query":{
"match":{
"category":"红米"
}
}
}
注意
我们要查询的是红米,它会单个字拆开进行模糊查询,查出包含红或米的数据
10、全部查询请求体方式
http://47.108.170.87:9200/shopping/_search //GET Sent
{
"query":{
"match_all":{}
}
}
11、查询制定字段数据
http://47.108.170.87:9200/shopping/_search //GET Sent
{
"query":{
"match_all":{}
},
"_source":["title"]
}
12、分页查询
http://47.108.170.87:9200/shopping/_search //GET Sent
{
"query":{
"match_all":{}
},
"from":0,
"size":2
}
13、排序查询
http://47.108.170.87:9200/shopping/_search //GET Sent
{
"query":{
"match_all":{}
},
"sort":{
"price":{
"order":"desc"
}
}
}
手机价格降序
14、多条件查询http://47.108.170.87:9200/shopping/_search //GET Sent
查询手机牌子是小米和价格是3999的手机
{
"query":{
"bool":{
"must":[{
"match":{
"category":"小米"
}
},{
"match":{
"price":3999.00
}
}]
}
}
}
15、范围查询
http://47.108.170.87:9200/shopping/_search //GET Sent
价格是大于2000的小米手机或者华为手机
{
"query":{
"bool":{
"should":[{
"match":{
"category":"小米"
}
},{
"match":{
"category":"华为"
}
}]
},
"filter":{
"range":{
"price":{
"gt":2000
}
}
}
}
}
三、进阶检索
查询某个type下的所有数据
get 请求/test/student/_search 查询所有
四、Query DSL一个查询语句 的典型结构
{
"QUERY_NAME":{
"ARGUMENT": "VALUE",
"ARGUMENT1": "VALUE1",...
}
}
针对某个字段
{
"QUERY_NAME":{
"FIELD_NAME":{
"ARGUMENT":"VALUE",
"ARGUMENT1":"VALUE1"...
}
}
}
1、返回部分字段
GET bank/_search
{
"_source": ["balance","firstname"]
}
使用"_source"规定返回的字段名称
2、 match【匹配查询】基本类型(非字符串),精确匹配
GET bank/_search
{
"query": {
"match": {
"account_number": "20"
}
}
}
match 返回 account_number=20 的
字符串,全文检索
GET bank/_search
{
"query":{
"match":{
"address":"mill"
}
}
}
最终查询出 address 中包含 mill 单词的所有记录
match 当搜索字符串类型的时候,会进行全文检索,并且每条记录有相关性得分。
字符串,多个单词(分词+全文检索)
GET bank/_search
{
"query":{
"match":{
"address":"mill road"
}
}
}
最终查询出 address 中包含 mill 或者 road 或者 mill road 的所有记录,并给出相关性得分
全文检索最终会按照评分进行排序,会对检索条件进行分词匹配
3、match_phrase【短语匹配】
将需要匹配的值当成一个整体单词(不分词)进行检索
GET bank/_search
{
"query":{
"match_phrase":{
"address":"mill road"
}
}
}
查出 address 中包含 mill road 的所有记录,并给出相关性得分
4、 multi_match【多字段匹配】GET bank/_search
{
"query":{
"multi_match":{
"query":"mill",
"fields":[
"state",
"address"
]
}
}
}
查询的是state或者address中包含mill字段的
在这里插入图片描述
5、bool【复合查询】bool 用来做复合查询:
复合语句可以合并 任何 其它查询语句,包括复合语句,了解这一点是很重要的。这就意味着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。
must:必须达到 must 列举的所有条件
GET bank/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"address":"mill"
}
},
{
"match":{
"gender":"M"
}
}
]
}
}
}
在这里插入图片描述
should:应该达到 should 列举的条件,如果达到会增加相关文档的评分,并不会改变查询的结果。如果 query 中只有 should 且只有一种匹配规则,那么 should 的条件就会被作为默认匹配条件而去改变查询结果
GET bank/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"address":"mill"
}
},
{
"match":{
"gender":"M"
}
}
],
"should":[
{
"match":{
"address":"lane"
}
}
]
}
}
}
在这里插入图片描述
must_not 必须不是指定的情况
GET bank/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"address":"mill"
}
},
{
"match":{
"gender":"M"
}
}
],
"should":[
{
"match":{
"address":"lane"
}
}
],
"must_not":[
{
"match":{
"email":"baluba.com"
}
}
]
}
}
}
在这里插入图片描述
address 包含 mill,并且 gender 是 M,如果 address 里面有 lane 最好不过,但是 email 必
须不包含 baluba.com
在这里插入图片描述
6、 filter【结果过滤】
并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档。为了不计算分数 Elasticsearch 会自动检查场景并且优化查询的执行。
过滤不会计算相关性得分,只会筛选出满足条件的数据。
GET bank/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"address":"mill"
}
}
],
"filter":{
"range":{
"balance":{
"gte":10000,
"lte":20000
}
}
}
}
}
}
7、 term和 match 一样。匹配某个属性的值。
全文检索字段用 match,其他非 text 字段匹配用 term。
在这里插入图片描述
GET bank/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"age":{
"value":"28"
}
}
},
{
"match":{
"address":"990 Mill Road"
}
}
]
}
}
}
8、ggregations(执行聚合)
聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于 SQL GROUP
BY 和 SQL 聚合函数。在 Elasticsearch 中,您有执行搜索返回 hits(命中结果),并且同时返回聚合结果,把一个响应中的所有 hits(命中结果)分隔开的能力。这是非常强大且有效的, 您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的 API 来避免网络往返。
搜索address中包含mill的所有人的年龄分布以及平均年龄,但不显示这些人的详情。
GET bank/_search
{
"query":{
"match":{
"address":"mill"
}
},
"aggs":{
"group_by_state":{
"terms":{
"field":"age"
}
},
"avg_age":{
"avg":{
"field":"age"
}
}
},
"size":0
}
size:0 不显示搜索数据
aggs:执行聚合。聚合语法如下
"aggs": {
"aggs_name 这次聚合的名字,方便展示在结果集中": {
"AGG_TYPE 聚合的类型(avg,term,terms)": {}
}
},
在这里插入图片描述
复杂:
按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
GET bank/account/_search
{
"query":{
"match_all":{
}
},
"aggs":{
"age_avg":{
"terms":{
"field":"age",
"size":1000
},
"aggs":{
"banlances_avg":{
"avg":{
"field":"balance"
}
}
}
}
},
"size":1000
}
在这里插入图片描述
复杂
查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资
GET bank/account/_search
{
"query":{
"match_all":{
}
},
"aggs":{
"age_agg":{
"terms":{
"field":"age",
"size":100
},
"aggs":{
"gender_agg":{
"terms":{
"field":"gender.keyword",
"size":100
},
"aggs":{
"balance_avg":{
"avg":{
"field":"balance"
}
}
}
},
"balance_avg":{
"avg":{
"field":"balance"
}
}
}
}
},
"size":1000
}
在这里插入图片描述
五、MappingMapping(映射)
Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。比如,使用 mapping 来定义:
1、新版本改变Es7 及以上移除了 type 的概念。
关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用, 但ES 中不是这样的。elasticsearch 是基于 Lucene 开发的搜索引擎,而 ES 中不同 type 下名称相同的 filed 最终在 Lucene 中的处理方式是一样的。
两个不同 type 下的两个user_name,在 ES 同一个索引下其实被认为是同一个 filed, 你必须在两个不同的 type 中定义相同的 filed 映射。否则,不同 type 中的相同字段名称就会在处理中出现冲突的情况,导致 Lucene 处理效率下降。
去掉 type 就是为了提高 ES 处理数据的效率。
Elasticsearch 7.x
URL 中的 type 参数为可选。比如,索引一个文档不再要求提供文档类型。
Elasticsearch 8.x
不再支持 URL 中的 type 参数。
解决:
将索引从多类型迁移到单类型,每种类型文档一个独立索引
将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移
创建映射
创建索引并指定映射
PUT /my-index
{
"mappings":{
"properties":{
"age":{
"type":"integer"
},
"email":{
"type":"keyword"
},
"name":{
"type":"text"
}
}
}
}
在这里插入图片描述
添加新的字段映射
index控制字段是否被检索到
PUT /my-index/_mapping
{
"properties":{
"employee-id":{
"type":"keyword",
"index":false
}
}
}
在这里插入图片描述
更新映射
对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移。
数据迁移
先创建出 new_twitter 的正确映射。然后使用如下方式进行数据迁移
POST _reindex [固定写法]
{
"source":{
"index":"twitter"
},
"dest":{
"index":"new_twitter"
}
}
将旧索引的type下的数据进行迁移
POST _reindex
{
"source":{
"index":"twitter",
"type":"tweet"
},
"dest":{
"index":"tweets"
}
}