精确查找
当进行精确值查找时,我们会使用过滤器(filters),因为整个过程不会计算相关度,所以它们执行的速度非常快。
term查找数字
如何通过Elasticsearch进行精确值的插叙
SELECT document
FROM products
WHERE price = 20;
在Elasticsearch的查询表达式(query DSL)中,我们可以使用term来达到目的
#方式1
GET /my_store/products/_search
{
"query":{
"term":{
"price":20
}
}
}
#方式2
GET /my_store/products/_search
{
"query":{
"constant_score":{
"filter":{
"term":{
"price":20
}
}
}
}
}
方式1和方式2的区别在于当查询一个精确值的时候,我们不希望对查询进行评分计算。只希望对文档进行包括或排除计算,所以使用constant_score查询以非评分模式来执行term查询并以 1 作为统一评分。
term查找文本
如果我们对productID进行查询
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"term" : {
"productID" : "XHDK-A-1293-#fJ3"
}
}
}
}
}
通过分析命令(分析API)我们可以看到字段会被分解成什么样的数据
GET /my_store/_analyze
{
"field":"productID",
"text":"XHDK-A-1293-#fJ3"
}
这是因为默认情况下,string类型的数据在写入是的时候会被分词器分解,因此是无法进行准确值查询,我们可以在创建索引的时候设置mapping,需要准确查询的项不需要分解。
PUT /my_store
{
"mappings": {
"products": {
"properties": {
"productID": {
"type": "keyword"
},
"price":{
"type":"integer"
}
}
}
}
}
组合过滤器
如何使用Elasticsearch实现以下的SQL
SELECT product
FROM products
WHERE (price = 20 OR productID = "XHDK-A-1293-#fJ3")
AND (price != 30)
需要使用bool(布尔)过滤器
{
"bool":{
"must": [],
"should": [],
"must_not":[]
}
}
-
must
所有的语句都 必须(must) 匹配,和 AND 等价
-
must_not
所有的语句都 不能(must not) 匹配,与 NOT 等价
-
should
至少有一个语句要匹配,与 OR 等价
GET /my_store/products/_search
{
"query":{
"bool":{
"should":[
{"term":{"price":20}},
{"term":{"productID":"XHDK-A-1293-#fJ3"}}
],
"must_not":{
"term":{"price":30}
}
}
}
}
注意事项
[1] 需要使用一个 filtered 查询将所有的东西保存起来
嵌套布尔过滤器
尽管bool是一个复合过滤器,可以接受多个子过滤器,需要注意的是bool也是一个过滤器,这就意味着它也可以嵌套在其他的bool过滤器中。
SELECT document
FROM products
WHERE productID = "KDKE-B-9947-#kL5"
OR ( productID = "JODL-X-1937-#pV7"
AND price = 30 )
现在将该SQL转化成嵌套bool
GET /my_store/products/_search
{
"query": {
"bool":{
"should":[
{"term":{"productID":"KDKE-B-9947-#kL5"}},
{
"bool":{
"must":[
{"term":{"productID":"JODL-X-1937-#pV7"}},
{"term":{"price":30}}
]
}
}
]
}
}
}
查找多个精确值
如何查找多个精确值
{
"terms":{
"price":[20,30]
}
}
与term一样,terms也需要将查询体放置到filter中使用
GET /my_store/products/_search
{
"query": {
"constant_score": {
"filter": {
"terms": {
"price": [
20,
30
]
}
},
"boost": 1.0
}
}
}
包含、而非相等
一定要了解term和terms是包含(contains)操作,而不是相等(equals)操作。比如我们有一个词项term过滤器
{"term":{"tags":"search"},它会和一下两个文档同时匹配
{"tags":["search"]}
{"tags":["search","open_source"]
精确相等
如上,如何做到完全相等,最好的方式增加一个字段。
{"tags":["search"],"tag_count":1}
{"tags":["search","open_source"],"tag_count":2}
则通过以下查询语句达到准确的查询
GET /my_store/products/_search
{
"query":{
"constant_score":{
"filter":{
"bool":{
"must":[
{"term":{"tags":"search"}},
{"term":{"tag_count":1}}
]
}
}
}
}
}
范围查找
现在,我们开始学习如何使用范围查找
SELECT document
FROM products
WHERE price BETWEEN 20 AND 40;
在Elasticsearch中,使用range来表达范围查询
{
"range":{
"gte":20,
"lte":40
}
}
range提供包含(inclusive)和不包含(exclusive)这两种范围表达式
- gt : 大于
- gte : 大于等于
- lt : 小于
- lte : 小于等于
举个范围查询的例子
GET /my_store/products/_search
{
"query":{
"constant_score":{
"filter":{
"range":{
"price":{
"gt":10,
"lte":30
}
}
}
}
}
}
日期范围查找
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-07 00:00:00"
}
}
计算过去一个小时之内的文档
"range" : {
"timestamp" : {
"gt" : "now-1h"
}
}
也可以通过数学表达式来进行
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-01 00:00:00||+1M"
}
}
字符串也可以进行范围查找
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
处理null值
在Elasticsearch中,因为是表字段是动态的,因此可能在一个索引中的数据有的文档存在tags的字段,有的可能不存在或者是空数组,有的可能是多个值。
因为倒排索引只是一个token列表和相关文档信息,如果字段不存在,则不会持有任何token,也就是在倒排索引中是无法体现出来的。
最终,这就意味着 null ,[] 和[null]都是等价的,因为都在倒排索引中无法体现出来。
POST /my_index/posts/_bulk
{ "index": { "_id": "1" }}
{ "tags" : ["search"] }
{ "index": { "_id": "2" }}
{ "tags" : ["search", "open_source"] }
{ "index": { "_id": "3" }}
{ "other_field" : "some data" }
{ "index": { "_id": "4" }}
{ "tags" : null }
{ "index": { "_id": "5" }}
{ "tags" : ["search", null] }
存在字段
现在在这样一个文档中,如何实现以下SQL效果
SELECT tags
FROM posts
WHERE tags IS NOT NULL
查询结构体如下
GET /my_index/posts/_search
{
"query":{
"constant_score":{
"filter":{
"exists":{"field":"tags"}
}
}
}
}
查询缺失字段
GET /my_index/posts/_search
{
"query":{
"constant_score":{
"filter":{
"bool":{
"must_not":[
{"exists":{"field":"tags"}}
]
}
}
}
}
}
对象缺失查询
不仅可以过滤核心类型, exists and missing 查询 还可以处理一个对象的内部字段。以下面文档为例:
{
"name" : {
"first" : "John",
"last" : "Smith"
}
}
我们不仅可以检查 name.first 和 name.last 的存在性,也可以检查 name ,不过在 映射 中,如上对象的内部是个扁平的字段与值(field-value)的简单键值结构,类似下面这样:
{
"name.first" : "John",
"name.last" : "Smith"
}
那么我们如何用 exists 或 missing 查询 name 字段呢? name 字段并不真实存在于倒排索引中。
原因是当我们执行下面这个过滤的时候:
{
"exists" : { "field" : "name" }
}
实际执行的是:
{
"bool": {
"should": [
{ "exists": { "field": "name.first" }},
{ "exists": { "field": "name.last" }}
]
}
}
这也就意味着,如果 first 和 last 都是空,那么 name 这个命名空间才会被认为不存在。