
2.4 词项级查询
Elasticsearch拥有一种专门的查询类型——词项级查询,用于支持查询结构化数据。数值、日期、范围、IP地址等属于结构化文本类型。Elasticsearch对待结构化数据和非结构化数据的方式有所不同:非结构化(全文)数据会被分析,而结构化字段则按原样存储。
让我们回顾一下图书文档,看一下 edition、amazon_rating和release_date字段(在代码清单2-15中用粗体展示)。
代码清单2-15 一个样本图书文档
{ "title": "Effective Java", "author": "Joshua Bloch", "synopsis": "A must-have book for every Java programmer and Java, ...", "edition": 3, "amazon_rating": 4.7, "release_date": "2017-12-27", ... }
当我们第一次索引文档时,由于我们没有预先创建索引,Elasticsearch会通过分析字段的值来推断出模式。例如,edition字段被表示为数值(非文本)字段,因此会被引擎推断为long数据类型。
按照类似的逻辑,amazon_rating字段被确定为float数据类型,因为该字段包含小数。release_date被确定为date数据类型,因为这个值以国际标准ISO 8601的日期格式(yyyy-MM-dd)表示。这3个字段都被归类为非文本(non-text)字段,这意味着它们的值不会被分词(不会被拆分成词元),也不会被归一化(没有同义词或词根),而是按原样存储。
词项级查询只会产生两种输出:如果查询与条件相匹配,则返回结果;否则,不返回任何结果。这些查询不考虑文档的匹配程度(相关性),而是专注于查询是否有匹配。由于不考虑相关性,因此词项级查询不会产生相关性分数。在本节中我们看几个词项级查询的例子。
2.4.1 term查询
term查询用于获取与搜索条件中提供的值精确匹配的结果。例如,要获取所有第3版的书,我们可以编写一个term查询,如代码清单2-16所示。
代码清单2-16 获取第3版的书
GET books/_search { "_source": ["title","edition"], ←--- 在响应文档中只返回两个字段 "query": { "term": { ←--- 声明这是一个词项级查询 "edition": { ←--- 提供字段和值作为搜索条件 "value": 3 } } } }
这个查询返回了所有第3版的书(我们的索引中只有1本书,即Effective Java),如下所示:
"hits" : [{ ... "_score" : 1.0, "_source" : { "title" : "Effective Java", "edition" : 3, ... } }]
如果仔细观察结果你会发现,结果的默认分数是1.0,就像我之前提到的,词项级查询并不关心相关性。
2.4.2 range查询
range查询用于获取匹配某个范围的结果,例如获取从凌晨1:00到下午1:00之间的航班,或者找到年龄在14岁到19岁之间的青少年。range查询是搜索范围数据的强大工具,可以应用于日期、数值和其他属性。
继续图书的例子。我们可以使用range查询来获取所有amazon_rating高于或等于4.5星且低于或等于5星的书,如代码清单2-17所示。
代码清单2-17 使用range查询获取评分在4.5星到5星之间的书
GET books/_search { "query": { "range": { ←--- 声明range查询 "amazon_rating": { ←--- 匹配的范围 "gte": 4.5, ←--- gte:大于或等于 "lte": 5 ←--- lte:小于或等于 } } }}
这个range查询将获取3本书,因为有3本书的评分高于或等于4.5星(为简洁起见,省略了输出结果)。
还有几种词项级查询,包括terms查询、ids查询、exists查询、prefix查询等。我将在第8~10章中更详细地介绍这几种词项的查询。
到目前为止,我已经介绍了一些根据基本条件获取结果时可能有用的查询,例如匹配书名、在多个字段中搜索一个单词、查找评分最高的书等。但实际上,查询可能更复杂,例如获取Joshua撰写的评分高于4.5星且于2015年后出版的第1版的书。幸运的是,Elasticsearch提供了高级查询类型,以便我们可以使用这些高级查询以复合查询(compound query)的方式来满足复杂的搜索条件。下面我们就来看一个复合查询的例子。