Elasticsearch权威指南 阅读笔记(4) 结构化查询
目录:
结构化查询
请求体查询
GET /_search
查询多个索引或者类型
GET /index_2014*/type1,type2/_search
可以使用from及size参数进行分页
GET /_search
{
"from": 30,
"size": 10
}
因为HTTP语义和内容RPC中未规定GET请求中允许携带交互数据,所以有些HTTP服务支持,而另一些(特别是缓存代理)则不允许这种情况,所以可以使用
POST /_search
{
"from": 30,
"size": 10
}
同理适用于GET请求的API中
结构化查询
结构化查询依赖的就是Lucene的能力,适用query参数
GET /_search
{
"query": YOUR_QUERY_HERE
}
空查询可以匹配的就是
GET /_search
{
"query": {
"match_all": {}
}
}
使用match_all查询子句
查询字句
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
或者向一个指定字段FIELD_NAME
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
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
}
}
查询与过滤
结构化查询(Query DSL)和结构化过滤(Filter DSL)
过滤语句会询问每个文档的字段值是否包含着特定值
- created的日期范围是否在2013到2014 ?
- status字段中是否包含单词"published" ?
- lat_lon字段中的地理位置与目标点相距是否不超过10km ?
过滤比查询效率要高,并且易于缓存。
- 使用过滤语句得到的结果集是一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。
- 查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗时,并且查询结果也不可缓存。
- 过滤语句的目的就是缩小匹配的文档结果集
最重要的查询过滤语句
term过滤
主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型)
{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}
{ "term": { "public": true }}
{ "term": { "tag": "full_text" }}
terms过滤
允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配
{
"terms": {
"tag": [ "search", "full_text", "nosql" ]
}
}
range过滤
按照指定范围查找一批数据
{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
- gt 大于
- gte 大于等于
- lt 小于
- lte 小于等于
exists 和 missing过滤
查找文档中是否包含指定字段或没有某个字段
{
"exists": {
"field": "title"
}
}
bool过滤
来合并多个过滤条件查询结果的布尔逻辑
- must 多个查询条件的完全匹配,相当于 and。
- must_not 多个查询条件的相反匹配,相当于 not。
- should 至少有一个查询条件匹配, 相当于 or。
match_all查询
查询到所有文档,没有查询条件下的默认语句
{
"match_all": {}
}
match查询
一个标准查询,如果你使用match查询一个全文本字段,它会在真正查询之前用分析器先分析match一下查询字符
{
"match": {
"tweet": "About Search"
}
}
如果用match下指定了一个确切值,在遇到数字,日期,布尔值或者not_analyzed的字符串时,它将为你搜索你给定的值
不过如果是过滤的话,最好用term
multi_match查询
match查询的基础上同时搜索多个字段
{
"multi_match": {
"query": "full text search",
"fields": [ "title", "body" ]
}
}
bool查询
bool查询与bool过滤相似,用于合并多个查询子句。不同的是,bool过滤可以直接给出是否匹配成功, 而bool查询要计算每一个查询子句的 _score(相关性分值)
查询将会找到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" }}}
]
}
}
查询与过滤条件的合并
带过滤的查询语句
{
"match": {
"email": "business opportunity"
}
}
让这条语句加入 term 过滤
{
"term": {
"folder": "inbox"
}
}
search API中只能包含query语句,所以我们需要用filtered来同时包含"query"和"filter"子句
GET /_search
{
"query": {
"filtered": {
"query": { "match": { "email": "business opportunity" }},
"filter": { "term": { "folder": "inbox" }}
}
}
}
单条过滤语句
GET /_search
{
"query": {
"filtered": {
"filter": { "term": { "folder": "inbox" }}
}
}
}
一条查询语句没有指定查询范围,那么它默认使用match_all查询
GET /_search
{
"query": {
"filtered": {
"query": { "match_all": {}},
"filter": { "term": { "folder": "inbox" }}
}
}
}
查询语句中的过滤
一条带有查询功能 的过滤语句, 这条语句可以过滤掉看起来像垃圾邮件的文档
GET /_search
{
"query": {
"filtered": {
"filter": {
"bool": {
"must": { "term": { "folder": "inbox" }},
"must_not": {
"query": {
"match": { "email": "urgent business proposal" }
}
}
}
}
}
}
}
过滤语句中可以使用query查询的方式代替bool过滤子句。在filter中只能有过滤字句吧,所以用query,我的理解是这样的
很少用到的过滤语句中包含查询,保留这种用法只是为了语法的完整性。 只有在过滤中用到全文本匹配的时候才会使用这种结构。
验证查询
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"
}
}
}
响应结果为
{
"valid" : false,
"_shards" : { ... },
"explanations" : [ {
"index" : "gb",
"valid" : false,
"error" : "org.elasticsearch.index.query.QueryParsingException:
[gb] No query registered for [tweet]"
} ]
}
所以这边正确的请求应该是
GET /_validate/query?explain
{
"query": {
"match" : {
"tweet" : "really powerful"
}
}
}
返回的结果是带有查询语句的可阅读描述, 可以帮助了解查询语句在ES中是如何执行的
{
"valid" : true,
"_shards" : { ... },
"explanations" : [ {
"index" : "us",
"valid" : true,
"explanation" : "tweet:really tweet:powerful"
}, {
"index" : "gb",
"valid" : true,
"explanation" : "tweet:really tweet:power"
} ]
}
explanation会为每一个索引返回一段描述,match 是如何为查询字符串 "really powerful" 进行查询的
- 首先,它被拆分成两个独立的词分别在 tweet 字段中进行查询。
- 而且,在索引us中这两个词为"really"和"powerful",在索引gb中被拆分成"really" 和 "power"。 这是因为我们在索引gb中使用了english分析器