elasticsearnch结构化查询

一. 请求体查询

request body search API,参数为json格式
空查询
空查询将会返回索引中所有的文档

GET /_search
{}

同字符串查询一样,你可以查询一个,多个或_all索引(indices)或类型(types)

GET /index_2014*/type1,type2/_search
{}

你可以使用from及size参数进行分页

GET /_search
{
  "from": 30,
  "size": 10
}

GET请求中携带数据了,有些HTTP服务允许这种行为,而另一些(特别是缓存代理),则不允许这种行为。
所以也接收post请求

POST /_search
{
  "from": 30,
  "size": 10
}

请求体查询允许我们使用结构化查询Query DSL(Query Domain Specific Language)

二. 结构化查询

需要传递query参数

GET /_search
{
    "query": YOUR_QUERY_HERE
}

空查询 - {} - 在功能上等同于使用match_all查询子句

GET /_search
{
    "query": {
        "match_all": {}
    }
}

查询子句
一个查询子句一般使用这种结构:

{
    QUERY_NAME: {
        ARGUMENT: VALUE,
        ARGUMENT: VALUE,...
    }
}

或指向一个指定的字段:

{
    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

复合子句可以合并多种子句为一个单一的查询,无论是叶子子句还是其他的复合子句
以下实例查询的是邮件正文中含有“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 ?
一条查询语句与过滤语句相似,但问法不同:
查询语句会询问每个文档的字段值与特定值的匹配程度如何?
查询语句的典型用法是为了找到文档:
查找与 full text search 这个词语最佳匹配的文档

  • 查找包含单词 run ,但是也包含runs, running, jog 或 sprint的文档
  • 同时包含着 quick, brown 和 fox,单词间离得越近,该文档的相关性越高
  • 标识着 lucene, search 或 java,标识词越多,该文档的相关性越高
    一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且 按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索。

四. 最重要的查询过滤语句

term 过滤
term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型):

    { "term": { "age":    26           }}
    { "term": { "date":   "2014-09-01" }}
    { "term": { "public": true         }}
    { "term": { "tag":    "full_text"  }}

terms 过滤
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:

{
    "terms": {
        "tag": [ "search", "full_text", "nosql" ]
        }
}

range 过滤
range过滤允许我们按照指定范围查找一批数据

{
    "range": {
        "age": {
            "gte":  20,
            "lt":   30
        }
    }
}

范围操作符包含:

gt :: 大于
gte:: 大于等于
lt :: 小于
lte:: 小于等于

exists 和 missing 过滤
exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件

{
    "exists":   {
        "field":    "title"
    }
}

对于已经查出的数据,区分某个字段是否可用

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   }}
        ]
    }
}

match_all 查询
使用match_all 可以查询到所有文档,是没有查询条件下的默认语句

{
    "match_all": {}
}

所有结果的相关性相同,_score都为1
match 查询
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"  }}

做精确匹配搜索时,你最好用过滤语句,因为过滤语句可以缓存数据
match查询不可以用类似"+usid:2 +tweet:search"这样的语句。 它只能就指定某个确切字段某个确切的值进行搜索

multi_match 查询
multi_match查询允许你做match查询的基础上同时搜索多个字段

{
    "multi_match": {
        "query":    "full text search",
        "fields":   [ "title", "body" ]
    }
}

bool 查询
bool 查询与 bool 过滤相似,用于合并多个查询子句
bool 过滤可以直接给出是否匹配成功
而bool 查询要计算每一个查询子句的 _score (相关性分值)

must:: 查询指定文档一定要被包含。
must_not:: 查询指定文档一定不要被包含。
should:: 查询指定文档,有则可以为文档相关性加分。

如果bool 查询下没有must子句,那至少应该有一个should子句。但是 如果有must子句,那么没有should子句也可以进行查询

{
    "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" 子句:

{
    "filtered": {
        "query":  { "match": { "email": "business opportunity" }},
        "filter": { "term":  { "folder": "inbox" }}
    }
}

我们在外层再加入 query 的上下文关系

GET /_search
{
    "query": {
        "filtered": {
            "query":  { "match": { "email": "business opportunity" }},
            "filter": { "term": { "folder": "inbox" }}
        }
    }
}

单条过滤语句
在 query 上下文中,如果你只需要一条过滤语句,比如在匹配全部邮件的时候,你可以 省略 query 子句:

GET /_search
{
    "query": {
        "filtered": {
            "filter":   { "term": { "folder": "inbox" }}
        }
    }
}

如果一条查询语句没有指定查询范围,那么它默认使用 match_all 查询,所以上面语句 的完整形式如下:

GET /_search
{
    "query": {
        "filtered": {
            "query":    { "match_all": {}},
            "filter":   { "term": { "folder": "inbox" }}
        }
    }
}

查询语句中的过滤
有时候,你需要在 filter 的上下文中使用一个 query 子句。下面的语句就是一条带有查询功能 的过滤语句, 这条语句可以过滤掉看起来像垃圾邮件的文档:

GET /_search
{
    "query": {
        "filtered": {
            "filter":   {
                "bool": {
                    "must":     { "term":  { "folder": "inbox" }},
                    "must_not": {
                        "query": { <1>
                            "match": { "email": "urgent business proposal" }
                        }
                    }
                }
            }
        }
    }
}

过滤语句中可以使用query查询的方式代替 bool 过滤子句
我们很少用到的过滤语句中包含查询,保留这种用法只是为了语法的完整性。 只有在过滤中用到全文本匹配的时候才会使用这种结构。

六. 验证查询

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 <1>
{
   "query": {
      "tweet" : {
         "match" : "really powerful"
      }
   }
}

explain 参数可以提供语句错误的更多详情

{
  "valid" :     false,
  "_shards" :   { ... },
  "explanations" : [ {
    "index" :   "gb",
    "valid" :   false,
    "error" :   "org.elasticsearch.index.query.QueryParsingException:
                 [gb] No query registered for [tweet]"
  } ]
}

理解查询语句
如果是合法语句的话,使用 explain 参数可以返回一个带有查询语句的可阅读描述, 可以帮助了解查询语句在ES中是如何执行的

GET /_validate/query?explain
{
   "query": {
      "match" : {
         "tweet" : "really powerful"
      }
   }
}

explanation 会为每一个索引返回一段描述,因为每个索引会有不同的映射关系和分析器:

{
  "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分析器。

posted @ 2016-09-23 10:46  zhangshihai1232  阅读(115)  评论(0)    收藏  举报