就会用多无聊,看点别的

检索文档

GET /blog/_doc/3?pretty

根据indextypeid搜索文档

在任意的查询字符串增加pretty参数,美化输出,但_source字段不会被美化,结果会与输入保持一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index" : "blog",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"_seq_no" : 2,
"_primary_term" : 1,
"found" : true,
"_source" : {
"contect" : 3,
"date" : "2019-07-23"
}
}

空搜索

没有指定任何查询条件

1
GET /_search

返回集群中所有索引下的所有文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.0,
"hits": [{
"_index": "blog",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"contect": 1,
"date": "2019-07-21"
}
}]
}
}

took:执行整个搜索请求耗费的毫秒数

timed_out:是否超时。如果响应时间比完成结果更重要,可以指定:10ms十毫秒或1s一秒。在超时之前,会返回已经从每个分片获取的结果。

timeout不是停止执行查询,仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接。在后台,其他的分片可能仍在执行查询即使是结果已经被发送了。

使用超时是因为SLA( 服务等级协议)是更重要的,而不是因为想去中止长时间运行的查询。

_shards:查询中参与分片的总数,以及这些分片成功、失败的个数,被跳过的(跳过的原因?)

hits

total:匹配到的文档总数,一个hits数组包含所查询结果的前十个文档

source:可以直接从返回的结果中使用整个文档。不像其他的搜索引擎(其他的哪些?),仅仅返回文档的ID,需要单独去获取文档

_score:匹配度。文档按照_score降序排列。1是中性的

路由

当索引一个文档,它被存储在单独一个主分片上。Elasticsearch是如何知道文档属于哪个分片的呢?创建一个新文档时,它是如何知道是应该存储在分片1还是分片2上的呢?

进程不能是随机的,因为将来要检索文档。事实上,它根据一个简单的算法决定:

shard = hash(routing) % number_of_primary_shards

routing:任意字符串,默认是_id,支持自定义。

  • logstash中修改output中的routing值,es中不做修改。
1
2
3
4
5
6
7
8
9
output {
elasticsearch {
hosts => "http://localhost:9200"
index => "movies"
document_id => "%{id}"
routing => "%{category} ###关键字
}
stdout {}
}

kibana查询时:

1
GET /movies/_search?routing=api ###routing指定是字段中具体的值
  • 指定routing参数
1
2
3
4
5
POST /blog/_doc?routing=2019-01-04
{
"contect":4,
"date":"2019-01-04"
}

会按照日期将文档置于同一分片上


其他:

  • 在所有索引中搜索:/_search
  • 在单索引搜索:/blog/_search
  • 在多索引中搜索:/blog,movie/_search
  • 模糊搜索: /b*/_search

搜索一个索引有5个主分片和5个索引各有一个分片事实上是一样的。

document模型设计

对于MySQL,尽量避免一些复杂查询,在Elasticsearch中,应同样避免复杂查询,会影响性能。

对于计算的部分,在应用中完成,将计算后的数据直接写入es中。搜索的时候,就不需要利用es的搜索语法来完成复杂查询,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。

分页

如果想看第11个文档,怎么办?

和SQL使用LIMIT关键字返回只有一页的结果一样,Elasticsearch接受fromsize参数:

1
2
size: 结果数,默认10
from: 跳过开始的结果数,默认0

如果想每页显示5个结果,页码从1到3,那请求如下:

1
2
3
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10

应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。

假如每页10条数据,查询第100页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上,如果你有个 5 个shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。

分布式的,你要查第100页的10条数据,不可能说从5个 shard,每个 shard 就查 2 条数据?最后到协调节点合并成 10 条数据?你必须得从每个 shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长。非常坑爹。所以用 es 做分页的时候,你会发现越翻到后面,就越是慢。

我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10秒 才能查出来一页数据了。

在集群系统中深度分页

为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它再排序这所有的50个结果以选出顶端的10个结果。

现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序这50050个结果并丢弃50040个!

可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何语句不能返回多于1000个结果的原因。

img

  • filesystem cache

es 的搜索引擎严重依赖于底层的 filesystem cache,你如果给 filesystem cache 更多的内存,尽量让内存可以容纳所有的 idx segment file 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。

把一些热点数据,提前访问刷到filesystem cache,再次搜索时,直接走内存。

  • 冷热分离

冷数据写入一个索引中,热数据写入另外一个索引中,这样可以确保热数据在被预热后,尽量都留在filesystem cache中,别让冷数据给冲刷掉。


es建索引写入数据,数据最先是存在内存buffer里的,然后再刷入到lucene的底层文件segment中;
写入segment完毕后再执行refresh操作,refresh操作后,数据将commit到磁盘中。
数据刷入到了磁盘,就可以执行查询操作了。

过程简单描述如下:内存buffer–>segment–>refresh–>磁盘

注意,这些过程,会有translog记录;translog存在的意义就是保证数据刷入的可靠性;
es建索引写入数据的过程是内存到磁盘的过程,这个过程有日志的记录,
那就是translog,当数据还在内存里没刷到磁盘中时,如果服务器down了又没translog机制的话,
那么数据就会丢失,有了translog,服务器down机后再起来,就能很快恢复写入的过程。

这里要注意的是,translog也是先存在内存里的,然后默认5秒刷一次写到硬盘里。

那么如何高效的检索大量文档?