结构化搜索
结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程。比如日期、时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作。比较常见的操作包括比较数字或时间的范围,或判定两个值的大小。
文本也可以是结构化的。如彩色笔可以有离散的颜色集合: 红(red)
、 绿(green)
、 蓝(blue)
。一个博客可能被标记了关键词 分布式(distributed)
和 搜索(search)
。电商网站上的商品都有 UPCs(通用产品码 Universal Product Codes)或其他的唯一标识,它们都需要遵从严格规定的、结构化的格式。
在结构化查询中,我们得到的结果***总是是否,要么存于集合之中,要么存在集合之外。结构化查询不关心文件的相关度或评分***;它简单的对文档包括或排除处理。
这在逻辑上是能说通的,因为一个数字不能比其他数字 更 适合存于某个相同范围。结果只能是:存于范围之中,抑或反之。同样,对于结构化文本来说,一个值**要么相等,要么不等***。没有 更似 这种概念
精确值查找
当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。我们会在本章后面的 过滤器缓存 中讨论过滤器的性能优势,不过现在只要记住:请尽可能多的使用过滤式查询。
term 查询数字
我们首先来看最为常用的 term
查询, 可以用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text)。
准备
让我们以下面的例子开始介绍,创建并索引一些表示产品的文档,文档里有字段 price
和 productID
( 价格
和 产品ID
):
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,如果我们将其用 SQL 形式表达,会是下面这样:
select *
from products
where price = 20
在 Elasticsearch 的查询表达式(query DSL)中,我们可以使用 term
查询达到相同的目的。 term
查询会查找我们指定的精确值。作为其本身, term
查询是简单的。它接受一个字段名以及我们希望查找的数值:
{
"term" : {
"price" : 20
}
}
通常当查找一个精确值的时候,我们不希望对查询进行评分计算。只希望对文档进行包括或排除的计算,所以我们会使用 constant_score
查询以非评分模式来执行 term
查询并以一作为统一评分。
最终组合的结果是一个 constant_score
查询,它包含一个 term
查询:
GET /my_store/products/_search
{
"query" : {
"constant_score" : { //(1)
"filter" : {
"term" : { //(2)
"price" : 20
}
}
}
}
}
- (1)我们用 constant_score 将 term 查询转化成为过滤器
- (2)term 查询
执行后,这个查询所搜索到的结果与我们期望的一致:只有文档 2 命中并作为结果返回(因为只有 2
的价格是 20
):
"hits" : [
{
"_index" : "my_store",
"_type" : "products",
"_id" : "2",
"_score" : 1.0, //(1)
"_source" : {
"price" : 20,
"productID" : "KDKE-B-9947-#kL5"
}
}
]
- (1)查询置于
filter
语句内不进行评分或相关度的计算,所以所有的结果都会返回一个默认评分1.0
term 查询文本
如本部分开始处提到过的一样 ,使用 term
查询匹配字符串和匹配数字一样容易。如果我们想要查询某个具体 UPC ID 的产品,使用 SQL 表达式会是如下这样:
SELECT product
FROM products
WHERE productID = "XHDK-A-1293-#fJ3"
转换成查询表达式(query DSL),同样使用 term
查询,形式如下:
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"productID" : "XHDK-A-1293-#fJ3"
}
}
}
}
}
但这里有个小问题:我们无法获得期望的结果。为什么呢?问题不在 term
查询,而在于索引数据的方式。 如果我们使用 analyze
API (分析 API),我们可以看到这里的 UPC 码被拆分成多个更小的 token :
GET /my_store/_analyze
{
"field": "productID",
"text": "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>"