以前咱们全部的查询都属于命令行查询,可是不利于复杂的查询,并且通常在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,可是,若是想要善用搜索,咱们必须使用请求体查询(request body search)API。之因此这么称呼,是由于大多数的参数以JSON格式所容纳而非查询字符串。请求体查询,并不只仅用来处理查询,并且还能够高亮返回结果中的片断,而且给出帮助你的用户找寻最好结果的相关数据建议。html
咱们以最简单的search
API开始,空查询将会返回索引中全部的文档。java
GET /_search {}
同字符串查询同样,能够查询一个,多个或_all索引(indices
)或类型(types
):sql
也可使用from及size参数进行分页:数组
GET /_search { "from": 30, "size": 10 }
须要注意的是:携带内容的GET请求?缓存
任何一种语言(特别是js)的HTTP库都不容许GET请求中携带交互数据。 事实上,有些用户很惊讶GET请求中竟然会容许携带交互数据。nosql
真实状况是,http://tools.ietf.org/html/rfc7231#page-24[RFC 7231], 一份规定HTTP语义及内容的RFC中并未规定GET请求中容许携带交互数据! 因此,有些HTTP服务容许这种行为,而另外一些(特别是缓存代理),则不容许这种行为。elasticsearch
Elasticsearch的做者们倾向于使用GET提交查询请求,由于他们以为这个词相比POST来讲,能更好的描述这种行为。然而,由于携带交互数据的GET请求并不被普遍支持,因此searchAPI一样支持POST请求,相似于这样:ide
POST /_search { "from": 30, "size": 10 }
这个原理一样应用于其余携带交互数据的GET API请求中。工具
结构化查询是一种灵活的,多表现形式的查询语言。 Elasticsearch在一个简单的JSON接口中用结构化查询来展示Lucene绝大多数能力。 你应当在你的产品中采用这种方式进行查询。它使得你的查询更加灵活,精准,易于阅读而且易于debug。性能
使用结构化查询,你须要传递query参数:
GET /_search { "query": 发查询体放置于此便可 }
空查询 - {} - 在功能上等同于使用match_all查询子句,正如其名字同样,匹配全部的文档:
GET /_search { "query": { "match_all": {} #查询体 } }
一个查询子句通常使用这种结构:
#整个属于查询体 { QUERY_NAME(查询命令): { ARGUMENT: VALUE, ARGUMENT: VALUE,... } }
或指向一个指定的字段:
#整个属于查询体 { QUERY_NAME(查询命令): { FIELD_NAME(匹配字段): { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } }
例如,你可使用match查询子句用来找寻在tweet字段中找寻包含,elasticsearch的成员:
{ "match"(查询命令): { "tweet": "elasticsearch" } }
完整的查询请求会是这样:
GET /_search { "query": { "match": { "tweet": "elasticsearch" } } }
查询子句就像是搭积木同样,能够合并简单的子句为一个复杂的查询语句,好比:
leaf clauses
)(好比match
子句)用以在将查询字符串与一个字段(或多字段)进行比较compound
)用以合并其余的子句。例如,bool
子句容许你合并其余的合法子句,must
,must_not
或者should
,若是可能的话:{ "bool": { "must": { "match": { "tweet": "elasticsearch" }}, "must_not": { "match": { "name": "mary" }}, "should": { "match": { "tweet": "full text" }} } }
复合子句能合并任意其余查询子句,包括其余的复合子句。这就意味着复合子句能够相互嵌套,从而实现很是复杂的逻辑。
如下实例查询的是邮件正文中含有“business opportunity”字样的星标邮件或收件箱中正文中含有“business opportunity”字样的非垃圾邮件:
#整个属于查询体 { "bool": { "must": { "match": { "email": "business opportunity" }}, "should": [ { "match": { "starred": true }}, { "bool": { "must": { "folder": "inbox" }, "must_not": { "spam": true } }} ], "minimum_should_match": 1 } }
Elasticsearch使用的DSL具备一组称为查询的组件,它们能够混合并以无穷组合进行匹配。这一组组件能够在两个上下文中使用:过滤上下文和查询上下文。
当用于过滤上下文时,该查询被称为“非评分”或“过滤”查询。也就是说,查询只询问问题:“此文档是否匹配?”。答案老是一个简单的二进制yes|no。
created
的日期范围是否在 2013 到 2014 ?status
字段中是否包含单词 "published" ?lat_lon
字段中的地理位置与目标点相距是否不超过10km ?当在查询上下文中使用时,查询变为“评分”查询。相似于其非评分兄弟,这肯定文档是否匹配以及文档匹配的程度。
查询的典型用法:
full text search
这个词语最佳匹配的文档run
,可是也包含runs
, running
, jog
或 sprint
的文档quick
, brown
和 fox
--- 单词间离得越近,该文档的相关性越高lucene
, search
或 java
--- 标识词越多,该文档的相关性越高评分查询计算每一个文档与查询的相关程度,并为其分配相关性_score,稍后用于按相关性对匹配文档进行排序。这种相关性的概念很是适合于全文搜索,其中不多有彻底“正确”的答案。
新特性:历史上,查询和过滤器是Elasticsearch中的单独组件。从Elasticsearch 2.0开始,过滤器在技术上被消除,而且全部查询都得到了成为非评分的能力。
然而,为了清楚和简单,将使用term
“过滤器”来表示在非评分过滤上下文中使用的查询。能够将term
“过滤器”,“过滤查询”和“非评分查询”视为相同。
相似地,若是单独使用term
“查询”而不使用限定符,指的是“评分查询”。
关于具体的Query DSL
变化能够查看Query DSL changes。
过滤查询是对集合包含/排除的简单检查,这使得计算很是快。当您的过滤查询中至少有一个是“稀疏”(匹配文档较少)时,能够利用各类优化,而且能够将常用的非评分查询缓存在内存中以便更快地访问。
相比之下,评分查询不只必须找到匹配的文档,并且还要计算每一个文档的相关程度,这一般使得他们比他们的非评分对手更重。此外,查询结果不可缓存。
因为倒排索引,只匹配几个文档的简单评分查询可能与跨越数百万个文档的过滤器同样好或更好。然而,通常来讲,过滤器将赛过评分查询。
过滤的目的是减小必须由评分查询检查的文档的数量。
做为通常规则,对全文搜索或任何会影响相关性分数的条件使用查询子句,并对其余全部条件使用过滤器。
match_all
查询只匹配全部文档。若是未指定任何查询,则是使用的默认查询:
{“match_all”:{}}
此查询常常与过滤器结合使用,例如,用于检索收件箱文件夹中的全部电子邮件。全部文件被认为是同等相关的,因此他们都得到1的中性分数。
match
查询是一个标准查询,无论你须要全文本查询仍是精确查询基本上都要用到它。
若是你使用match
查询一个全文本字段,它会在真正查询以前用分析器先分析match
一下查询字符:
{ "match": { "tweet": "About Search" } }
若是用match下指定了一个确切值,在遇到数字,日期,布尔值或者not_analyzed
的字符串时,它将为你搜索你给定的值:
{ "match": { "age": 26 }} { "match": { "date": "2014-09-01" }} { "match": { "public": true }} { "match": { "tag": "full_text" }}
提示: 作精确匹配搜索时,你最好用过滤语句,由于过滤语句能够缓存数据。
不像咱们在ElasticSearch 5学习(4)——简单搜索笔记中介绍的字符查询,match查询不能够用相似"+usid:2 +tweet:search"这样的语句。 它只能就指定某个确切字段某个确切的值进行搜索,而你要作的就是为它指定正确的字段名以免语法错误。
multi_match
查询容许你作match
查询的基础上同时搜索多个字段:
{ "multi_match": { "query": "full text search", "fields": [ "title", "body" ] } }
range过滤容许咱们按照指定范围查找一批数据:
{ "range": { "age": { "gte": 20, "lt": 30 } } }
范围操做符包含:
gt :: 大于
gte:: 大于等于
lt :: 小于
lte:: 小于等于
term
用于按照精确值进行搜索,不管是数字,日期,布尔值仍是未分析的精确值字符串字段:
{ "term": { "age": 26 }} { "term": { "date": "2014-09-01" }} { "term": { "public": true }} { "term": { "tag": "full_text" }}
term
不对输入文本执行分析,所以它将精确查找提供的值。
terms
查询与term
查询相同,但容许您指定多个值进行匹配。若是字段包含任何指定的值,则文档匹配:
{ "terms": { "tag": [ "search", "full_text", "nosql" ] }}
与term
查询相似,不对输入文本执行分析。它正在寻找精确匹配(包括大小写,重音,空格等)。
exists
和missing
查询用于查找指定字段具备一个或多个值(exists
)或没有任何值(missing
)的文档。
它在本质上相似于SQL中的IS_NULL
(缺失)和NOT IS_NULL
(存在):
{ "exists": { "field": "title" } }
这些查询常常用于仅在存在字段时应用条件,以及在缺乏条件时应用不一样的条件。
现实世界的搜索请求历来不简单;他们使用各类输入文本搜索多个字段,并根据条件数组进行过滤。要构建复杂的搜索,您须要一种将多个查询组合到一个搜索请求中的方法。
要作到这一点,你可使用bool
询。此查询在用户定义的布尔组合中将多个查询组合在一块儿。此查询接受如下参数:
bool 过滤能够用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操做符:
must :: 多个查询条件的彻底匹配,至关于 and。
must_not :: 多个查询条件的相反匹配,至关于 not。
should :: 至少有一个查询条件匹配, 至关于 or。
这些参数能够分别继承一个过滤条件或者一个过滤条件的数组:
{ "bool": { "must": { "term": { "folder": "inbox" }}, "must_not": { "term": { "tag": "spam" }}, "should": [ { "term": { "starred": true }}, { "term": { "unread": true }} ] } }
由于这是咱们见过的第一个包含其余查询的查询,因此咱们须要谈论分数是如何组合的。每一个子查询子句将单独计算文档的相关性分数。一旦计算了这些分数,bool查询将将分数合并在一块儿,并返回表示布尔运算的总分数的单个分数。
如下查询将会找到 title
字段中包含 "how to make millions",而且 tag
字段没有被标为 "spam"。 若是有标识为 "starred" 或者发布日期为2014年以前,那么这些匹配的文档将比同类网站等级高:
{ "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }}, { "range": { "date": { "gte": "2014-01-01" }}} ] } }
提示: 若是bool
查询下没有must
子句,那至少应该有一个should
子句。可是若是有must
子句,那么没有should
子句也能够进行查询。
若是咱们不但愿文档的日期影响评分,咱们能够从新排列前面的示例以使用过滤子句:
{ "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "range": { "date": { "gte": "2014-01-01" }} } } }
范围查询已从should
子句中移出并进入过滤器子句。
经过将范围查询移动到过滤子句中,咱们将其转换为非评分查询。它将再也不为文档的相关性排名贡献分数。而且由于它如今是一个非评分查询,它可使用可用于过滤器的各类优化,这应该提升性能。
任何查询均可以以这种方式使用。只需将查询移动到bool
查询的过滤器子句中,它就会自动转换为非评分过滤器。
若是你须要过滤许多不一样的标准,bool
查询自己能够用做非评分查询。只需将它放在过滤器子句中,并继续构建布尔逻辑:
{ "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "bool": { "must": [ { "range": { "date": { "gte": "2014-01-01" }}}, { "range": { "price": { "lte": 29.99 }}} ], "must_not": [ { "term": { "category": "ebooks" }} ] } } } }
经过在filter
子句中嵌入bool
查询,咱们能够为咱们的过滤条件添加布尔逻辑。
尽管不像bool
查询那样常用,可是constant_score
查询在你的工具箱中仍然有用。查询对全部匹配的文档应用静态,常数得分。它主要用于当你想执行一个过滤器,没有别的(例如没有评分查询)。你可使用它而不是一个只有过滤器子句的bool
。性能将是相同的,但它能够帮助查询简单/清晰。
{ "constant_score": { "filter": { "term": { "category": "ebooks" } } } }
查询语句能够变得很是复杂,特别是与不一样的分析器和字段映射相结合后,就会有些难度。
validate
API 能够验证一条查询语句是否合法。
GET /gb/tweet/_validate/query { "query": { "tweet" : { "match" : "really powerful" } } }
以上请求的返回值告诉咱们这条语句是非法的:
{ "valid" : false, "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 } }
要找出为何它无效,请将explain参数添加到查询字符串:
GET /gb/tweet/_validate/query?explain { "query": { "tweet" : { "match" : "really powerful" } } }
显然,咱们已经将查询(match)类型与字段名称(tweet)混淆:
{ "valid" : false, "_shards" : { ... }, "explanations" : [ { "index" : "gb", "valid" : false, "error" : "org.elasticsearch.index.query.QueryParsingException: [gb] No query registered for [tweet]" } ] }
使用explain
参数具备返回(有效)查询的可读描述的附加优势,这对理解Elasticsearch如何解释查询是有用的:
GET /gb/tweet/_validate/query?explain { "query": { "tweet" : { "match" : "really powerful" } } }
为每一个咱们查询的索引返回一个解释,由于每一个索引能够有不一样的映射和分析器:
{ "valid" : true, "_shards" : { ... }, "explanations" : [ { "index" : "us", "valid" : true, "explanation" : "tweet:really tweet:powerful" }, { "index" : "gb", "valid" : true, "explanation" : "tweet:realli tweet:power" } ] }
从解释中,您能够看到查询字符串的match
查询really powerful
已被重写为对tweet
字段的两个单项查询,每一个term
一个。
此外,对于咱们的索引,这两个term
是really
和powerful
的,而对于gb
索引,term
是realli
和power
。缘由是咱们改变了gb
索引中的tweet
字段以使用english
分析器。
转载请注明出处。
做者:wuxiwei
出处:http://www.cnblogs.com/wxw16/p/6204644.html