最近,需要用到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. poj 3614 奶牛美容问题 优先队列

    题意:每头奶牛需要涂抹防晒霜,其中有效的范围 min~max ,现在有L种防晒霜,每种防晒霜的指数为 f 瓶数为 l,问多少只奶牛可以涂上合适的防晒霜?思路: 优先队列+贪心 当奶牛的 min< ...

  2. LA 6538 Dinner Coming Soon DP

    题意: 给出一个有\(N\)个顶点\(M\)条有向边的图,起点为\(1\),终点为\(N\). 每条边有经过的时间,和经过这条边的花费.一开始你有\(R\)元钱,要在\(T\)时间内赶到终点去约会. ...

  3. curl download zip file

    https://askubuntu.com/questions/285976/download-zip-file-with-curl-command

  4. ogre3D程序实例解析1-平移旋转与缩放

    接着上篇写 http://www.cnblogs.com/songliquan/p/3294902.html 旋转 这里有必要看一下关于旋转的源代码:    virtual void pitch(co ...

  5. C/C++、Java、Python谁是编译型语言,谁是解释型语言?

    最近各大互联网公司线上笔试,编程题目里的编译器只支持C/C++.Java,甚至有的支持javaScrpit和Pascal,就是不支持Python.让一直以来用惯了Python的我直吐血,于是今天痛定思 ...

  6. iOS----精品开源库-开发强力助攻

    30个精品iOS开源库,超强助攻 你不会想错过他们,真的. 我爱开源.  文章的尾部你会看到一个太长不看的版本——一个简单的列表,只有标题和到项目的链接.如果你发现这篇文章是有用的,把它和你的iOS开 ...

  7. iOS学习笔记35-社交分享

    一.社交分享 现在很多应用都内置“社交分享”功能,可以将看到的新闻.博客.广告等内容分享到微博.微信.QQ.人人网等,其实从iOS6.0开始苹果官方就内置了Social.framework专门来实现社 ...

  8. 皮尔逊相关系数的计算(python代码版)

    from math import sqrt def multipl(a,b): sumofab=0.0 for i in range(len(a)): temp=a[i]*b[i] sumofab+= ...

  9. hihoCoder #1117 战争年代

    题目大意 对一棵树的节点染色.初始时每个点都染成颜色 $0$,然后进行 $m$ 轮操作.第 $i$ 轮操作:从 $[0,d_i]$ 中随机选出一个整数 $d$,将距离点 $x_i$ 不超过 $d$ 的 ...

  10. for语句执行顺序

    for语句的结构如下所示: for(初始化;条件;调整) { 示例语句; } 第一次顺序:初始化 ->条件->示例语句 第二次顺序:调整->条件->示例语句 第三次顺序:调整- ...