Elasticsearch 权威教程 - 搜索——基本的工具
2018-02-28 22:55
218 查看
搜索——基本的工具
到目前为止,我们已经学会了如何使用elasticsearch作为一个简单的NoSQL风格的分布式文件存储器——我们可以将一个JSON文档扔给Elasticsearch,也可以根据ID检索它们。但Elasticsearch真正强大之处在于可以从混乱的数据中找出有意义的信息——从大数据到全面的信息。这也是为什么我们使用结构化的JSON文档,而不是无结构的二进制数据。Elasticsearch不只会存储(store)文档,也会索引(indexes)文档内容来使之可以被搜索。
每个文档里的字段都会被索引并被查询。而且不仅如此。在简单查询时,Elasticsearch可以使用所有的索引,以非常快的速度返回结果。这让你永远不必考虑传统数据库的一些东西。
A search can be:
搜索(search)可以:
在类似于
gender或者
age这样的字段上使用结构化查询,
join_date这样的字段上使用排序,就像SQL的结构化查询一样。
全文检索,可以使用所有字段来匹配关键字,然后按照关联性(relevance)排序返回结果。
或者结合以上两条。
很多搜索都是开箱即用的,为了充分挖掘Elasticsearch的潜力,你需要理解以下三个概念:
概念 | 解释 |
---|---|
映射(Mapping) | 数据在每个字段中的解释说明 |
分析(Analysis) | 全文是如何处理的可以被搜索的 |
领域特定语言查询(Query DSL) | Elasticsearch使用的灵活的、强大的查询语言 |
我们将使用最简单的形式开始介绍
searchAPI.
测试数据
本章节测试用的数据可以在这里被找到https://gist.github.com/clintongormley/8579281你可以把这些命令复制到终端中执行以便可以实践本章的例子。
空搜索
最基本的搜索API表单是空搜索(empty search),它没有指定任何的查询条件,只返回集群索引中的所有文档:GET /_search
响应内容(为了编辑简洁)类似于这样:
{ "hits" : { "total" : 14, "hits" : [ { "_index": "us", "_type": "tweet", "_id": "7", "_score": 1, "_source": { "date": "2014-09-17", "name": "John Smith", "tweet": "The Query DSL is really powerful and flexible", "user_id": 2 } }, ... 9 RESULTS REMOVED ... ], "max_score" : 1 }, "took" : 4, "_shards" : { "failed" : 0, "successful" : 10, "total" : 10 }, "timed_out" : false }
hits
响应中最重要的部分是hits,它包含了
total字段来表示匹配到的文档总数,
hits数组还包含了匹配到的前10条数据。
hits数组中的每个结果都包含
_index、
_type和文档的
_id字段,被加入到
_source字段中这意味着在搜索结果中我们将可以直接使用全部文档。这不像其他搜索引擎只返回文档ID,需要你单独去获取文档。
每个节点都有一个
_score字段,这是相关性得分(relevance score),它衡量了文档与查询的匹配程度。默认的,返回的结果中关联性最大的文档排在首位;这意味着,它是按照
_score降序排列的。这种情况下,我们没有指定任何查询,所以所有文档的相关性是一样的,因此所有结果的
_score都是取得一个中间值
1
max_score指的是所有文档匹配查询中
_score的最大值。
took
took告诉我们整个搜索请求花费的毫秒数。
shards
_shards节点告诉我们参与查询的分片数(
total字段),有多少是成功的(
successful字段),有多少的是失败的(
failed字段)。通常我们不希望分片失败,不过这个有可能发生。如果我们遭受一些重大的故障导致主分片和复制分片都故障,那这个分片的数据将无法响应给搜索请求。这种情况下,Elasticsearch将报告分片
failed,但仍将继续返回剩余分片上的结果。
timeout
time_out值告诉我们查询超时与否。一般的,搜索请求不会超时。如果响应速度比完整的结果更重要,你可以定义
timeout参数为
10或者
10ms(10毫秒),或者
1s(1秒)
GET /_search?timeout=10ms
Elasticsearch将返回在请求超时前收集到的结果。
超时不是一个断路器(circuit breaker)(译者注:关于断路器的理解请看警告)。
警告
需要注意的是timeout不会停止执行查询,它仅仅告诉你目前顺利返回结果的节点然后关闭连接。在后台,其他分片可能依旧执行查询,尽管结果已经被发送。
使用超时是因为对于你的业务需求(译者注:SLA,Service-Level Agreement服务等级协议,在此我翻译为业务需求)来说非常重要,而不是因为你想中断执行长时间运行的查询。
多索引和多类别
你注意到空搜索的结果中不同类型的文档——user和
tweet——来自于不同的索引——
us和
gb。
通过限制搜索的不同索引或类型,我们可以在集群中跨所有文档搜索。Elasticsearch转发搜索请求到集群中平行的主分片或每个分片的复制分片上,收集结果后选择顶部十个返回给我们。
通常,当然,你可能想搜索一个或几个自定的索引或类型,我们能通过定义URL中的索引或类型达到这个目的,像这样:
/_search
在所有索引的所有类型中搜索/gb/_search
在索引gb的所有类型中搜索
/gb,us/_search
在索引gb和
us的所有类型中搜索
/g*,u*/_search
在以g或
u开头的索引的所有类型中搜索
/gb/user/_search
在索引gb的类型
user中搜索
/gb,us/user,tweet/_search
在索引gb和
us的类型为
user和
tweet中搜索
/_all/user,tweet/_search
在所有索引的user和
tweet中搜索
search types
userand
tweetin all indices
当你搜索包含单一索引时,Elasticsearch转发搜索请求到这个索引的主分片或每个分片的复制分片上,然后聚集每个分片的结果。搜索包含多个索引也是同样的方式——只不过或有更多的分片被关联。
重要
搜索一个索引有5个主分片和5个索引各有一个分片事实上是一样的。接下来,你将看到这些简单的情况如何灵活的扩展以适应你需求的变更。
分页
《空搜索》一节告诉我们在集群中有14个文档匹配我们的(空)搜索语句。但是只有10个文档在hits数组中。我们如何看到其他文档?
和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
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。
在集群系统中深度分页
为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它再排序这所有的50个结果以选出顶端的10个结果。现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序这50050个结果并丢弃50040个!
你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何语句不能返回多于1000个结果的原因。
TIP
在《重建索引》章节我们将阐述如何能高效的检索大量文档简易搜索
searchAPI有两种表单:一种是“简易版”的查询字符串(query string)将所有参数通过查询字符串定义,另一种版本使用JSON完整的表示请求体(request body),这种富搜索语言叫做结构化查询语句(DSL)
查询字符串搜索对于在命令行下运行点对点(ad hoc)查询特别有用。例如这个语句查询所有类型为
tweet并在
tweet字段中包含
elasticsearch字符的文档:
GET /_all/tweet/_search?q=tweet:elasticsearch
下一个语句查找
name字段中包含
"john"和
tweet字段包含
"mary"的结果。实际的查询只需要:
+name:john +tweet:mary
但是百分比编码(percent encoding)(译者注:就是url编码)需要将查询字符串参数变得更加神秘:
GET /_search?q=%2Bname%3Ajohn+%2Btweet%3Amary
"+"前缀表示语句匹配条件必须被满足。类似的
"-"前缀表示条件必须不被满足。所有条件如果没有
+或
-表示是可选的——匹配越多,相关的文档就越多。
_all
字段
返回包含"mary"字符的所有文档的简单搜索:
GET /_search?q=mary
在前一个例子中,我们搜索
tweet或
name字段中包含某个字符的结果。然而,这个语句返回的结果在三个不同的字段中包含
"mary":
用户的名字是“Mary”
“Mary”发的六个推文
针对“@mary”的一个推文
Elasticsearch是如何设法找到三个不同字段的结果的?
当你索引一个文档,Elasticsearch把所有字符串字段值连接起来放在一个大字符串中,它被索引为一个特殊的字段
_all。例如,当索引这个文档:
{ "tweet": "However did I manage before Elasticsearch?", "date": "2014-09-14", "name": "Mary Jones", "user_id": 1 }
这好比我们增加了一个叫做
_all的额外字段值:
"However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1"
若没有指定字段,查询字符串搜索(即q=xxx)使用
_all字段搜索。
TIP
_all字段对于开始一个新应用时是一个有用的特性。之后,如果你定义字段来代替
_all字段,你的搜索结果将更加可控。当
_all字段不再使用,你可以停用它,这个会在《全字段》章节阐述。
更复杂的语句
下一个搜索推特的语句:_allfield
*
name字段包含
"mary"或
"john"
*
date晚于
2014-09-10
*
_all字段包含
"aggregations"或
"geo"
+name:(mary john) +date:>2014-09-10 +(aggregations geo)
编码后的查询字符串变得不太容易阅读:
?q=%2Bname%3A(mary+john)+%2Bdate%3A%3E2014-09-10+%2B(aggregations+geo)
就像你上面看到的例子,简单(lite)查询字符串搜索惊人的强大。它的查询语法,会在《查询字符串语法》章节阐述。参考文档允许我们简洁明快的表示复杂的查询。这对于命令行下一次性查询或者开发模式下非常有用。
然而,你可以看到简洁带来了隐晦和调试困难。而且它很脆弱——查询字符串中一个细小的语法错误,像
-、
:、
/或
"错位就会导致返回错误而不是结果。
最后,查询字符串搜索允许任意用户在索引中任何一个字段上运行潜在的慢查询语句,可能暴露私有信息甚至使你的集群瘫痪。
TIP
因为这些原因,我们不建议直接暴露查询字符串搜索给用户,除非这些用户对于你的数据和集群可信。取而代之的,生产环境我们一般依赖全功能的请求体搜索API,它能完成前面所有的事情,甚至更多。在了解它们之前,我们首先需要看看数据是如何在Elasticsearch中被索引的。
原文:https://github.com/looly/elasticsearch-definitive-guide-cn
相关文章推荐
- Elasticsearch(搜索(1)--基本的工具)
- Elasticsearch 权威教程 - 分布式搜索的执行方式
- Elasticsearch 权威教程 - 结构化搜索
- Elasticsearch(搜索(2)--基本的工具)
- Elasticsearch 权威教程 - 多字段搜索
- hadoop基本教程之开源数据仓库工具hive
- 分布式搜索elasticsearch集群监控工具bigdesk
- Linux下的搜索工具find基本用法
- Lucene 6.2.1入门教程(一) 创建索引和基本搜索索引
- 分布式搜索elasticsearch集群管理工具head
- PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
- Elasticsearch 权威教程 - 映射和分析
- Elasticsearch 权威教程 - 控制关联
- ElasticSearch基本查询工具
- GDB工具使用教程_基本调试指令
- Elasticsearch 权威教程 - 请求体查询
- 【Lucene4.8教程之一】使用Lucene4.8进行索引及搜索的基本操作
- 分布式搜索elasticsearch集群监控工具bigdesk
- Elasticsearch: 权威指南(官方教程)
- JS模块化工具requirejs教程(二):基本知识