Elasticsearch深入搜索—结构化搜索

目录

第1关:Elastisearch精确值查找

代码

第2关:Elasticsearch多精确值查找以及Null值处理

代码


第1关:Elastisearch精确值查找

任务描述
本关任务:根据所学知识,查找产品 ID 为 KDKE-B-9947-#kL5 或者(产品 ID 为 ODL-X-1937-#pV7 并且价格为 30)的所有产品。

相关知识
为了完成本关任务,你需要掌握:

如何通过精确值查找数字和文本;
使用过滤器的方式进行精确查找;
如何组合多种过滤器。
当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。因此我们需要记住:请尽可能多的使用过滤式查询。

精确查找数字
我们首先来看最为常用的 term 查询,可以用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text)。

首先我们可以创建并索引一些表示产品的文档:

a.json 内容如下:

{ "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" }
插入文档:

curl -H "Content-Type: application/json" -XPOST 'http://127.0.0.1:9200/my_store/products/_bulk?pretty' --data-binary @a.json
如果我们想要找到具有某个价格的所有产品,我们可以使用 term 查询达到该目的。

term 查询会查找我们指定的精确值。作为其本身,term 查询是简单的。它接受一个字段名以及我们希望查找的数值:

{
    "query" : {
        "term" : {
            "price" : 20
        }
    }
}
通常当查找一个精确值的时候,我们不希望对查询进行评分计算。只希望对文档进行包括或排除的计算,所以我们会使用 constant_score 查询以非评分模式来执行 term 查询并以一作为统一评分。

最终组合的结果是一个 constant_score 查询,它包含一个 term 查询:

curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/my_store/products/_search?pretty' -d '
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "term" : {
                    "price" : 20
                }
            }
        }
    }
}'
我们用 constant_score 将 term 查询转化成为过滤器。

执行后,这个查询所搜索到的结果与我们期望的一致:只有文档 2 命中并作为结果返回(因为只有 2 的价格是 20):

{
...
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_store",
        "_type" : "products",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "price" : 20,
          "productID" : "KDKE-B-9947-#kL5"
        }
      }
    ]
  }
}
查询置于 filter 语句内不进行评分或相关度的计算,所以所有的结果都会返回一个默认评分 1。

term 查询文本
使用 term 查询匹配字符串和匹配数字一样容易。如果我们想要查询某个具体 UPC ID 的产品:

curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/my_store/products/_search?pretty' -d '
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "term" : {
                    "productID" : "XHDK-A-1293-#fJ3"
                }
            }
        }
    }
}'
但是,令我们惊讶的是,我们并没有查找到所需结果,这是为什么呢?

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}
问题不在 term 查询,而在于索引数据的方式。如果我们使用 analyze API (分析 API),我们可以看到这里的 UPC 码被拆分成多个更小的 token :

curl -H "Content-Type: application/json" -XGET 'http://localhost:9200/my_store/_analyze?pretty' -d '
{
  "field": "productID",
  "text": "XHDK-A-1293-#fJ3"
}'
执行结果:

{
  "tokens" : [
    {
      "token" : "xhdk",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "a",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "1293",
      "start_offset" : 7,
      "end_offset" : 11,
      "type" : "<NUM>",
      "position" : 2
    },
    {
      "token" : "fj3",
      "start_offset" : 13,
      "end_offset" : 16,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}
我们会发现以下几点不同:

Elasticsearch 用 4 个不同的 token 而不是单个 token 来表示这个 UPC;
所有字母都是小写的;
丢失了连接字符的 - 和 #。
所以当我们用 term 查询查找精确值 XHDK-A-1293-#fJ3 的时候,找不到任何文档,因为它并不在我们的倒排索引中,正如前面呈现出的分析结果,索引里有四个 token 。

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

为了避免这种问题,我们需要告诉 Elasticsearch 该字段具有精确值,要将其设置成精确值,无需分析的。 我们可以在自定义字段映射中查看它的用法。为了修正搜索结果,我们需要首先删除旧索引(因为它的映射不再正确)然后创建一个能正确映射的新索引:

# 首先删除旧索引
curl -XDELETE 'http://localhost:9200/my_store?pretty'
# 创建 _mapping 映射,设置其类型为 keyword,我们不想对 product

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小柒_02

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值