天天看点

ES结构化查询

Elasticsearch结构化查询

查找准确值

term用于数字
term主要用在处理数字,布尔值,日期和文本
GET /my_store/products/_search
{
    "query" : {
        "filtered" : { <>
            "query" : {
                "match_all" : {} <>
            },
            "filter" : {
                "term" : { <>
                    "price" : 
                }
            }
        }
    }
}
           
  1. filtered 查询同时接受 query 与 filter
  2. match_all 用来匹配所有文档,这是默认行为,所以在以后的例子中我们将省略掉 query 部分
  3. 这是我们上面见过的 term 过滤器,注意它在 filter 分句中的位置
term用于文本
内部过滤操作

组合过滤

布尔过滤器

bool 过滤器由三部分组成:

{
   "bool" : {
      "must" :     [],
      "should" :   [],
      "must_not" : [],
   }
}
           

must:所有分句都必须匹配,跟AND相同

must_not:所有分句都必须不匹配,跟NOT相同

should:至少有一个分句匹配,与OR相同

SELECT product
FROM   products
WHERE  (price =  OR productID = "XHDK-A-1293-#fJ3")
  AND  (price != )
# 转换成DSL
GET /my_store/products/_search
{
   "query" : {
      "filtered" : { <>
         "filter" : {
            "bool" : {
              "should" : [
                 { "term" : {"price" : }}, <>
                 { "term" : {"productID" : "XHDK-A-1293-#fJ3"}} <>
              ],
              "must_not" : {
                 "term" : {"price" : } <>
              }
           }
         }
      }
   }
}
           
嵌套布尔过滤器
虽然 bool 是一个组合过滤器而且接受子过滤器,需明白它自己仍然只是一个过滤器。这意味着你可以在 bool 过滤器中嵌套 bool 过滤器,让你实现更复杂的布尔逻辑
SELECT document
FROM   products
WHERE  productID      = "KDKE-B-9947-#kL5"
  OR (     productID = "JODL-X-1937-#pV7"
       AND price     =  )
# 转化为DSL
GET /my_store/products/_search
{
   "query" : {
      "filtered" : {
         "filter" : {
            "bool" : {
              "should" : [
                { "term" : {"productID" : "KDKE-B-9947-#kL5"}}, <>
                { "bool" : { <>
                  "must" : [
                    { "term" : {"productID" : "JODL-X-1937-#pV7"}}, <>
                    { "term" : {"price" : }} <>
                  ]
                }}
              ]
           }
         }
      }
   }
}
           
查询多个准确值
比起使用多个 term 过滤器,你可以用一个 terms 过滤器。terms 过滤器是 term 过滤器的复数版本
# 寻找 20 或 30 元的文档
GET /my_store/products/_search
{
    "query" : {
        "filtered" : {
            "filter" : {
                "terms" : { 
                    "price" : [, ]
                }
            }
        }
    }
}
           
term/terms:包含,而不是相等
term和terms都是包含操作,而不是相等操作

实例:过滤器{ “term” : { “tags” : “search” } }将匹配下面两个文档:

{ "tags" : ["search"] }
{ "tags" : ["search", "open_source"] }
           

工作原理:

term过滤器检查倒排索引中具有短语的文档,然后组成一个字节集,在我们简单实例中,我们有下面的倒排索引:

token docsIDs
open_source 2
search 1,2

当执行 term 过滤器来查询 search 时,它直接在倒排索引中匹配值并找出相关的 ID。如你所见,文档 1 和文档 2 都包含 search,所以他们都作为结果集返回。

提示: 倒排索引的特性让完全匹配一个字段变得非常困难。你将如何确定一个文档只能包含你请求的短语?你将在索引中找出这个短语,解出所有相关文档 ID,然后扫描 索引中每一行来确定文档是否包含其他值。

由此可见,这将变得非常低效和开销巨大。因此,term 和 terms 是 必须包含 操作,而不是 必须相等。

范围

range 过滤器既能包含也能排除范围,通过下面的选项:

  • gt: > 大于
  • lt: < 小于
  • gte: >= 大于或等于
  • lte: <= 小于或等于
SELECT document
FROM   products
WHERE  price BETWEEN  AND 
# 转化为DSL
GET /my_store/products/_search
{
    "query" : {
        "filtered" : {
            "filter" : {
                "range" : {
                    "price" : {
                        "gte" : ,
                        "lt"  : 
                    }
                }
            }
        }
    }
}
           

日期范围

"range" : {
    "timestamp" : {
        "gt" : "2014-01-01 00:00:00",
        "lt" : "2014-01-07 00:00:00"
    }
}
           

当用于日期字段时,range 过滤器支持日期数学操作。例如,我们想找到所有最近一个小时的文档:

"range" : {
    "timestamp" : {
        "gt" : "now-1h"
    }
}
           

这个过滤器将始终能找出所有时间戳大于当前时间减 1 小时的文档,让这个过滤器像移窗一样通过你的文档。

日期计算也能用于实际的日期,而不是仅仅是一个像 now 一样的占位符。只要在日期后加上双竖线 ||,就能使用日期数学表达式了。

# 早于 2014 年 1 月 1 号加一个月
"range" : {
    "timestamp" : {
        "gt" : "2014-01-01 00:00:00",
        "lt" : "2014-01-01 00:00:00||+1M" <>
    }
}
           

字符串范围

range 过滤器也可以用于字符串。字符串范围根据字典或字母顺序来计算。例如,这些值按照字典顺序排序:

* 5, 50, 6, B, C, a, ab, abb, abc, b

假如我们想让范围从 a 开始而不包含 b,我们可以用类似的 range 过滤器语法:

"range" : {
    "title" : {
        "gte" : "a",
        "lt" :  "b"
    }
}
           

当心基数:

数字和日期字段的索引方式让他们在计算范围时十分高效。但对于字符串来说却不是这样。为了在字符串上执行范围操作,Elasticsearch 会在这个范围内的每个短语执行 term 操作。这比日期或数字的范围操作慢得多。

字符串范围适用于一个基数较小的字段,一个唯一短语个数较少的字段。你的唯一短语数越多,搜索就越慢。

继续阅读