如果你没有听说过Elastic Stack,那你一定听说过ELK,实际上ELK是三款软件的简称,分别是Elasticsearch、
Logstash、Kibana组成,在发展的过程中,又有新成员Beats的加入,所以就形成了Elastic Stack。所以说,ELK是旧的称呼,Elastic Stack是新的名字。
Beats由如下组成:
ElasticSearch是一个基于Lucene的搜索服务器。 它提供了一一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。
官网:https://www.elastic.co/cn/elasticsearch
下载地址::https://www.elastic.co/cn/downloads/elasticsearch
解压即可
点击bin目录下的elasticsearch.bat即可启动服务器,
http://localhost:9200/
访问得到相关的版本信息
解决允许跨域访问
在 /config/elasticsearch.yml 文件最后添加如下代码
http.cors.enabled: true
http.cors.allow-origin: "*"
由于ES官方并没有为ES提供界面管理工具,仅仅是提供了后台的服务。elasticsearch-head是一个为ES开发的一个页面客户端工具,其源码托管于GitHub,
地址为:https://github.com/mobz/elasticsearch-head
安装启动
npm install
安装模块包npm run srart
即可后台启动elasticsearch-head的服务器在Elasticsearch中,提供了功能丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。
在Lucene中,创建索引是需要定义字段名称以及字段的类型的,在Elasticsearch中提供了非结构化的索引,就是不需要创建索引结构,即可写入数据到索引中,实际上在Elasticsearch底层会进行结构化操作,此操作对用户是透明的。
创建空索引:
put: 127.0.0.1:9200/hello
#第一个参数:分片数
#第二个参数:副本数
{
"settings":{
"index":{
"number_of_shards":"2",
"number_of_replicas":"0"
}
}
}
#删除索引
DELETE: 127.0.0.1:9200/hello
{
"acknowledged": true
}
URL规则:
POST /{索引}/{类型}/{id}
POST 127.0.0.1:9200/hello/user/1001
#数据
{
"id":1001,
"name":"张三",
"age":20,
"sex":"男"
}
#响应
{
"_index":"haoke",
"_type":"user",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":1,
"successful":1,
"failed":0
},
"_seq_no":0,
"_primary_term":1
}
不指定id插入数据:
POST 127.0.0.1:9200/hello/user/
{
"id":1002,
"name":"张三",
"age":20,
"sex":"男"
}
在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。
PUT 127.0.0.1:9200/hello/user/1001
{
"id":1001,
"name":"张三",
"age":21,
"sex":"女"
}
这时到数据已经被覆盖了,如果有字段没有值,那么值就为空
如果要局部更新
#注意:这里多了_update标识和"doc"
POST 127.0.0.1:9200/hello/user/1001_update
{
"doc":{
"age":23
}
}
可以看到数据已经被局部更新了。
在Elasticsearch中,删除文档数据,只需要发起DELETE请求即可。
DELETE 127.0.0.1:9200/hello/user/1001
需要注意的是,result表示已经删除,version也更加了。
如果删除一条不存在的数据,会响应404:
Get 127.0.0.1:9200/hello/user/1001
#响应数据
{
"_index": "hello",
"_type": "user",
"_id": "1001",
"_version": 3,
"found": true,
"_source": {
"id": 1001,
"name": "张三",
"age": 66,
"sex": "女"
}
}
Get 127.0.0.1:9200/hello/user/1001
#查询年龄等于20的用户
GET 127.0.0.1:9200/hello/user/_search?q=age:20
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。
DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。
#实现:查询年龄等于20的用户
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"match":{
"age":"20"
}
}
}
#实现:查询年龄大于30岁的男性用户。
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"bool":{
"filter":{
"range":{
"age":{
"gt":25
}
}
},
"must":{
"match":{
"sex":"男"
}
}
}
}
}
#实现:高亮显示
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"match":{
"name":"张三 李四"
}
},
"highlight":{
"fields":{
"name":{
}
}
}
}
#实现:聚合
在Elasticsearch中,支持聚合操作,类似SQL中的group by操作。
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"aggs":{
"all_interests":{
"terms":{
"field":"age"
}
}
}
}
索引
{
"settings":{
"index":{
"number_of_shards":"2",
"number_of_replicas":"0"
}
},
"mappings":{
"person":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"mail":{
"type":"keyword"
},
"hobby":{
"type":"text"
}
}
}
}
}
在Elasticsearch中,文档以JSON格式进行存储,可以是复杂的结构
可以在查询url后面添加pretty参数,使得返回的json更易查看。
在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回
GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT?_source=age,name
响应数据
{
"_index": "itcast",
"_type": "person",
"_id": "If6JeXEBTDVmGkzkSswT",
"_version": 1,
"found": true,
"_source": {
"name": "张三",
"age": 20
}
}
如不需要返回元数据,仅仅返回原始数据,可以这样:
GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT/_source
#响应数据
{
"name": "张三",
"age": 20,
"mail": "[email protected]",
"hobby": "羽毛球、乒乓球、足球"
}
还可以这样:
GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT/_source?_source=age,name
#响应数据
{
"name": "张三",
"age": 20
}
如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:
HEAD http://127.0.0.1:9200/itcast/person/1001/
如果文档存在:响应头信息状态码200
如果文档不存在:响应头信息状态码404
有些情况下可以通过批量操作以减少网络请求。如:批量查询、批量插入数据。
_mget
http://127.0.0.1:9200/itcast/person/_mget
{
"ids" : [ "1001", "1003" ]
}
如果,某一条数据不存在,不影响整体响应,需要通过found的值进行判断是否查询到数据。
在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。
请求格式如下:(请求格式不同寻常)
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...(这个一定要有一个换行)
注意:末尾一定要有一个换行
POST 127.0.0.1:9200/itcast/_bulk
{"create":{"_index":"haoke","_type":"user","_id":2001}}
{"id":2001,"name":"name1","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2002}}
{"id":2002,"name":"name2","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2003}}
{"id":2003,"name":"name3","age": 20,"sex": "男"}
POST 127.0.0.1:9200/itcast/_bulk
{"delete":{"_index":"haoke","_type":"user","_id":2001}}
{"delete":{"_index":"haoke","_type":"user","_id":2002}}
{"delete":{"_index":"haoke","_type":"user","_id":2003}}
由于delete没有请求体,所以,action的下一行直接就是下一个action。
其他操作类似。
一次请求多少性能最高?
通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。一个好的
批次最好保持在5-15MB大小间。
和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:
size: 结果数,默认10
from: 跳过开始的结果数,默认0
如果你想每页显示5个结果,页码从1到3,那请求如下:
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
GET 127.0.0.1:9200/hello/user/_search?size=2&from=2
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分
片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。
在集群系统中深度分页
们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一
页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它再
排序这所有的50个结果以选出顶端的10个结果。
现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的
10010个结果。然后请求节点排序这50050个结果并丢弃50040个!
你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何
语句不能返回多于1000个结果的原因。
前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类型的,否则,自动判断的类型和实际需求是不相符的。
自动判断的规则如下:
Elasticsearch中支持的类型如下:
注意
创建明确类型的索引:
PUT`127.0.0.1:9200/itcast
{
"settings":{
"index":{
"number_of_shards":"2",
"number_of_replicas":"0"
}
},
"mappings":{
"person":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"mail":{
"type":"keyword"
},
"hobby":{
"type":"text"
}
}
}
}
}
查看映射:
GET 127.0.0.1:9200/itcast/_mapping
插入数据:
POST 127.0.0.1:9200/itcast/_bulk
{"index":{"_index":"itcast","_type":"person"}}
{"name":"张三","age": 20,"mail": "[email protected]","hobby":"羽毛球、乒乓球、足球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"李四","age": 21,"mail": "[email protected]","hobby":"羽毛球、乒乓球、足球、篮球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"王五","age": 22,"mail": "[email protected]","hobby":"羽毛球、篮球、游泳、听音乐"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"赵六","age": 23,"mail": "[email protected]","hobby":"跑步、游泳"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"孙七","age": 24,"mail": "[email protected]","hobby":"听音乐、看电影"}
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"match":{
"hobby":"音乐"
}
}
}
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):
{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}
{ "term": { "public": true }}
{ "term": { "tag": "full_text" }}
#示例
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"term":{
"age":20
}
}
}
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"terms":{
"age" : [20,21]
}
}
}
range 过滤允许我们按照指定范围查找一批数据:
范围操作符包含:
gt :: 大于
gte :: 大于等于
lt :: 小于
lte :: 小于等于
示例
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"range":{
"age":{
"gte":20,
"lte":22
}
}
}
}
exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"exists":{
"field": "hobby"
}
}
}
match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符:
如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你
给定的值:
{ "match": { "age": 26 }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text" }}
这些参数可以分别继承一个查询条件或者一个查询条件的数组:
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"bool":{
"must":{
"match":{"hobby":"足球"}
},
"must_not":{
"match":{"hobby":"音乐"}
},
"should":[
{
"match":{
"hobby":"足球"
}
},
{
"match":{
"hobby":"羽毛球"
}
}
]
}
}
}
前面讲过结构化查询,Elasticsearch也支持过滤查询,如term、range、match等。
示例:查询年龄为20岁的用户。
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"bool":{
"filter":{
"term":{
"age":20
}
}
}
}
}
查询和过滤的对比
建议:
做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。
点击下载
链接:https://pan.baidu.com/s/1HJbA3Wsgbuqyd8pX4g7cpA
提取码:e506