最近,需要用到ES的一些常用的结构化搜索命令,因此,看了一些官方的文档,学习了一下。结构化查询指的是查询那些具有内在结构的数据,比如日期、时间、数字都是结构化的。

它们都有精确的格式,我们可以对这些数据进行逻辑操作,比较常见的操作包括比较时间区间,或者获取两个数字间的较大值。

精确查询

当进行精确查询时,过滤器filter是十分重要的,因为它们效率非常高,过滤器不计算相关性(直接跳过了整个记分阶段)而且很容易进行缓存。

过滤数字

我们首先看 term filter,它最常用,可以用来处理数字,布尔值,日期和文本。

例如我们有一些产品:

POST /my_store/products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10, "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20, "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30, "productID" : "QQPX-R-3956-#aD8" }

我们想要做的是要查询具有某个价格的所有产品,如果对于SQL熟悉,那么它的表达式是:

SELECT * FROM   products WHERE  price = 20

在ES查询中,我们使用 term 达到相同的目的:

{
"term" : {
"price" : 20
}
}

但是在ES里,term 不能单独使用,search API期望的是一个 query 而不是 filter,所以,我们需要把 term 放在一个filter query里进行使用:

GET /my_store/products/_search
{
"query" : {
"filtered" : { #filtered 查询同时接受一个 query 和 filter
"query" : {
"match_all" : {} #match_all 会返回所有匹配的文件,这是个默认行为
},
"filter" : {
"term" : { #term 过滤我们之前说到的,需要注意的是这里 term块 是处于 filter 之内的
"price" : 20
}
}
}
}
}

执行结果正如我们期望一样,它只会返回文档2,这里我们称为命中hit。

"hits" : [
{
"_index" : "my_store",
"_type" : "products",
"_id" : "2",
"_score" : 1.0, #1
"_source" : {
"price" : 20,
"productID" : "KDKE-B-9947-#kL5"
}
}
]

之前我们说到filter不会进行记分或相关性计算,这里的分数来自于我们查询时使用的关键字 match_all ,它会同等对待所有的文件,并对所有的结果都给以1的记分。

过滤文本

term 同样可以用来过滤文本,如果我们想要查询某个具体UPC id的产品,SQL语句会是下面这样:

SELECT product FROM   products WHERE  productID = "XHDK-A-1293-#fJ3"

转换成ES查询,同样使用 term 来查询:

GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"term" : {
"productID" : "XHDK-A-1293-#fJ3"
}
}
}
}
}

但这里有个小问题,我们没有如预期得到想要的结果!为什么呢?问题并不出在 term 查询上,问题出在数据索引的方式。如果使用 analyze API(Test Analyzers),我们可以看到这里的UPC码以及被拆分成多个小的token:

GET /my_store/_analyze?field=productID
XHDK-A-1293-#fJ3

结果

{
"tokens" : [ {
"token" : "xhdk",
"start_offset" : 0,
"end_offset" : 4,
"type" : "<ALPHANUM>",
"position" : 1
}, {
"token" : "a",
"start_offset" : 5,
"end_offset" : 6,
"type" : "<ALPHANUM>",
"position" : 2
}, {
"token" : "1293",
"start_offset" : 7,
"end_offset" : 11,
"type" : "<NUM>",
"position" : 3
}, {
"token" : "fj3",
"start_offset" : 13,
"end_offset" : 16,
"type" : "<ALPHANUM>",
"position" : 4
} ]
}

所以,当我们用 term 去过滤值 XHDK-A-1293-#fJ3 的时候,找不到任何文件,因为这个token不在我们的反向索引(inverted index)之中,正如上面呈现的,索引里面有4个token。

显然,这种对于id码或其他任何精确值的处理方式不是我们想要的。

为了避免这种问题,我们需要告诉ElasticSearch这个字段具有精确值,需要被设置成 not_analyzed 。 我们可以在定制化字段mapping中找到相关内容。为了修正这个问题,我们需要首先删除老的index,然后再创建一个新的

DELETE /my_store #1

PUT /my_store #2
{
"mappings" : {
"products" : {
"properties" : {
"productID" : {
"type" : "string",
"index" : "not_analyzed" #3
}
}
}
} }

然后我们就可以对文件重索引了:

POST /my_store/products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10, "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20, "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30, "productID" : "QQPX-R-3956-#aD8" }

组合过滤器

上面的两个例子都是单个filter的使用方式,在实际中,我们很多情况下会同时会对多个值或字段使用filter。例如,在ElasticSearch中,如何标识下面这个SQL?

SELECT product FROM   products WHERE  (price = 20 OR productID = "XHDK-A-1293-#fJ3") AND  (price != 30)

在这种情况下,我们需要 bool filter。这是一个复合过滤器可以接收多个参数,然后将他们组合成布尔组合。

布尔过滤器(Bool Filter)

bool filter包括三部分:

{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
  • must:所有的语句必须匹配,与 AND 等价。

  • must_not:所有的语句都不能匹配,与 NOT 等价。

  • should:至少有一个语句匹配,与 OR 等价。

用ES查询实现我们上面SQL里的查询:

GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : 20}},
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}}
],
"must_not" : {
"term" : {"price" : 30}
}
}
}
}
}
}

我们搜索的结果返回了2个hits,两个文件各满足其中一个条件:

"hits" : [
{
"_id" : "1",
"_score" : 1.0,
"_source" : {
"price" : 10,
"productID" : "XHDK-A-1293-#fJ3"
}
},
{
"_id" : "2",
"_score" : 1.0,
"_source" : {
"price" : 20,
"productID" : "KDKE-B-9947-#kL5"
}
}
]

嵌套布尔过滤器(Nesting Boolean Filters)

尽管 bool 是一个复合的过滤器,可以接受多个子过滤器,需要注意的是 bool 过滤器本身仍然是一个过滤器(filter)。这意味着我们可以将一个bool过滤器置于另外一个bool过滤器内部,这为我们提供了复杂布尔逻辑的处理能力:

对于一个SQL语句:

SELECT document FROM   products WHERE  productID  = "KDKE-B-9947-#kL5" OR ( productID = "JODL-X-1937-#pV7" AND price = 30 )

我们将其转换成一个嵌套的 bool 过滤器:

GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"productID" : "KDKE-B-9947-#kL5"}}, #1
{ "bool" : { #2
"must" : [
{ "term" : {"productID" : "JODL-X-1937-#pV7"}}, #3
{ "term" : {"price" : 30}} #4
]
}}
]
}
}
}
}
}

得到的结果有两个文件,他们各满足 should 中的一个条件:

"hits" : [
{
"_id" : "2",
"_score" : 1.0,
"_source" : {
"price" : 20,
"productID" : "KDKE-B-9947-#kL5" #1
}
},
{
"_id" : "3",
"_score" : 1.0,
"_source" : {
"price" : 30, #2
"productID" : "JODL-X-1937-#pV7" #3
}
}
]

ElasticSearch常用结构化搜索的更多相关文章

  1. elasticsearch 深入 —— 结构化搜索

    结构化搜索 结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程.比如日期.时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作.比较常见的操作 ...

  2. Elasticsearch系列---结构化搜索

    概要 结构化搜索针对日期.时间.数字等结构化数据的搜索,它们有自己的格式,我们可以对它们进行范围,比较大小等逻辑操作,这些逻辑操作得到的结果非黑即白,要么符合条件在结果集里,要么不符合条件在结果集之外 ...

  3. ElasticSearch 2 (13) - 深入搜索系列之结构化搜索

    ElasticSearch 2 (13) - 深入搜索系列之结构化搜索 摘要 结构化查询指的是查询那些具有内在结构的数据,比如日期.时间.数字都是结构化的.它们都有精确的格式,我们可以对这些数据进行逻 ...

  4. ElasticSearch 结构化搜索

    1.介绍 结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程.比如日期.时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作. 比较常见的操作 ...

  5. ElasticStack学习(九):深入ElasticSearch搜索之词项、全文本、结构化搜索及相关性算分

    一.基于词项与全文的搜索 1.词项 Term(词项)是表达语意的最小单位,搜索和利用统计语言模型进行自然语言处理都需要处理Term. Term的使用说明: 1)Term Level Query:Ter ...

  6. Elasticsearch结构化搜索与查询

    Elasticsearch 的功能之一就是搜索,搜索主要分为两种类型,结构化搜索和全文搜索.结构化搜索是指有关查询那些具有内在结构数据的过程.比如日期.时间和数字都是结构化的:它们有精确的格式,我们可 ...

  7. Elasticsearch 结构化搜索、keyword、Term查询

    前言 Elasticsearch 中的结构化搜索,即面向数值.日期.时间.布尔等类型数据的搜索,这些数据类型格式精确,通常使用基于词项的term精确匹配或者prefix前缀匹配.本文还将新版本的&qu ...

  8. ElasticSearch 结构化搜索全文

    1.介绍 上篇介绍了搜索结构化数据的简单应用示例,现在来探寻 全文搜索(full-text search) :怎样在全文字段中搜索到最相关的文档. 全文搜索两个最重要的方面是: 相关性(Relevan ...

  9. ElasticSearch(6)-结构化查询

    引用:ElasticSearch权威指南 一.请求体查询 请求体查询 简单查询语句(lite)是一种有效的命令行_adhoc_查询.但是,如果你想要善用搜索,你必须使用请求体查询(request bo ...

随机推荐

  1. Linux入门学习笔记2:终端命令

    LINUX操作系统学习 命令   附带建     cd   .. 当前路径的上一层       ../.. 当前路径的上两层       . 当前路径       - 跳转到上一次所在路径       ...

  2. python3中urllib库的request模块详解

    刚刚接触爬虫,基础的东西得时时回顾才行,这么全面的帖子无论如何也得厚着脸皮转过来啊! 原帖地址:https://www.2cto.com/kf/201801/714859.html 什么是 Urlli ...

  3. Applied Nonparametric Statistics-lec9

    Ref:https://onlinecourses.science.psu.edu/stat464/print/book/export/html/12 前面我们考虑的情况是:response是连续的, ...

  4. LeetCode(224) Basic Calculator

    题目 Implement a basic calculator to evaluate a simple expression string. The expression string may co ...

  5. poj-1011 sticks(搜索题)

    George took sticks of the same length and cut them randomly until all parts became at most 50 units ...

  6. apple苹果产品国行和港行的区别

    [iPhone国行和港行的区别]国行:耳机只能用在苹果设备上,不能用其它设备.充电器不用转接,直接可以用,保修的时候如果换新了,重新计算一年保修期.国行是三网通用.港行:耳机可以用在任何设备上.充电器 ...

  7. mac 命令行下连接到MySQL mysql: command not found

    mac下刚刚安装完MySQL后使用命令连接到MySQL mysql -uroot -p 提示:  -bash: mysql: command not found使用  /usr/local/mysql ...

  8. SDOJ 3696 Tree

    描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 输入 第一行V,E,need分别表示点数,边数和需要的白色边数. 接下来E行 每行 ...

  9. 创建sql作业(JOB)

    在SQL Server日常需求处理中,会遇到定时执行或统计数据的需求,这时我们可以通过作业(JOB)来处理,从而通过代理的方式来实现数据的自动处理.一下为SQL Server中创建作业的脚本,供大家参 ...

  10. 2018"百度之星"程序设计大赛 - 资格赛

    调查问卷  Accepts: 1546  Submissions: 6596  Time Limit: 6500/6000 MS (Java/Others)  Memory Limit: 262144 ...