Elasticsearch基本语法

ES结构化搜索

结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程。比如日期、时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作。比较常见的操作包括比较数字或时间的范围,或判定两个值的大小。

文本也可以是结构化的。如彩色笔可以有离散的颜色集合: 红(red) 、 绿(green) 、 蓝(blue) 。一个博客可能被标记了关键词 分布式(distributed) 和 搜索(search) 。电商网站上的商品都有 UPCs(通用产品码 Universal Product Codes)或其他的唯一标识,它们都需要遵从严格规定的、结构化的格式。

在结构化查询中,我们得到的结果 总是 非是即否,要么存于集合之中,要么存在集合之外。结构化查询不关心文件的相关度或评分;它简单的对文档包括或排除处理。

这在逻辑上是能说通的,因为一个数字不能比其他数字 更 适合存于某个相同范围。结果只能是:存于范围之中,抑或反之。同样,对于结构化文本来说,一个值要么相等,要么不等。没有 更似 这种概念。

 

空搜索

GET /_search

返回:

{
   "hits" : {
      "total" :       14,
      "hits" : [
        {
          "_index":   "us",
          "_type":    "tweet",
          "_id":      "7",
          "_score":   1,
          "_source": {
             "date":    "2014-09-17",
             "name":    "John Smith",
             "tweet":   "The Query DSL is really powerful and flexible",
             "user_id": 2
          }
       },
        ... 9 RESULTS REMOVED ...
      ],
      "max_score" :   1
   },
   "took" :           4,
   "_shards" : {
      "failed" :      0,
      "successful" :  10,
      "total" :       10
   },
   "timed_out" :      false
}

说明:

hits

返回结果中最重要的部分是 hits ,它 包含 total 字段来表示匹配到的文档总数,并且一个 hits 数组包含所查询结果的前十个文档。在 hits 数组中每个结果包含文档的 _index 、 _type 、 _id ,加上 _source 字段。这意味着我们可以直接从返回的搜索结果中使用整个文档。这不像其他的搜索引擎,仅仅返回文档的ID,需要你单独去获取文档。每个结果还有一个 _score ,它衡量了文档与查询的匹配程度。默认情况下,首先返回最相关的文档结果,就是说,返回的文档是按照 _score 降序排列的。在这个例子中,我们没有指定任何查询,故所有的文档具有相同的相关性,因此对所有的结果而言 1 是中性的 _score 。max_score 值是与查询所匹配文档的 _score 的最大值。


took
took 值告诉我们执行整个搜索请求耗费了多少毫秒。

shards
_shards 部分 告诉我们在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。正常情况下我们不希望分片失败,但是分片失败是可能发生的。如果我们遭遇到一种灾难级别的故障,在这个故障中丢失了相同分片的原始数据和副本,那么对这个分片将没有可用副本来对搜索请求作出响应。假若这样,Elasticsearch 将报告这个分片是失败的,但是会继续返回剩余分片的结果。

 

timeout
timed_out 值告诉我们查询是否超时。默认情况下,搜索请求不会超时。 如果低响应时间比完成结果更重要,你可以指定 timeout 为 10 或者 10ms(10毫秒),或者 1s(1秒):

GET /_search?timeout=10ms

在请求超时之前,Elasticsearch 将会返回已经成功从每个分片获取的结果。

 

精确值查找

当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。

term 查询数字

term 查询, 可以用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text)。

PS:中文慎用!!!中文匹配用 match_phrase,constant_score 查询以非评分模式来执行 term 查询并以一作为统一评分

sql: SELECT * FROM table WHERE  column=value;
es: 
GET /X/Y/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "column" : value
                }
            }
        }
    }
}
#X是索引名 Y是类型

 

过滤器

 布尔过滤器bool

 一个 bool 过滤器由三部分组成:

{
   "bool" : {
      "must" :     [],
      "should" :   [],
      "must_not" : [],
   }
}
# must
# 所有的语句都 必须(must) 匹配,与 AND 等价。
# must_not
# 所有的语句都 不能(must not) 匹配,与 NOT 等价。
# should
# 至少有一个语句要匹配,与 OR 等价。

eg1:

sql: SELECT * FROM table WHERE  (A= a OR B= b) AND (C!= c);
es: 
GET /X/Y/_search
{
   "query" : {
      "filtered" : { 
         "filter" : {
            "bool" : {
              "should" : [
                 { "term" : {"A" : a}}, 
                 { "term" : {"B" : b}} 
              ],
              "must_not" : {
                 "term" : {"C" : c} 
              }
           }
         }
      }
   }
}

eg2:

sql: SELECT * FROM table WHERE A= a OR ( B=b AND C=c);
eg: 
GET /X/Y/_search
{
   "query" : {
      "filtered" : {
         "filter" : {
            "bool" : {
              "should" : [
                { "term" : {"A" : a}}, 
                { "bool" : { 
                  "must" : [
                    { "term" : {"B" : b}}, 
                    { "term" : {"C" : c}} 
                  ]
                }}
              ]
           }
         }
      }
   }
}

 

查找多个精确值

terms 查找

sql: select * from table where A in (a1,a2);
es: 
GET /X/Y/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "terms" : { 
                    "A" : [a1, a2]
                }
            }
        }
    }
}

PS:term 和 terms 包含,而不是相等
一定要了解 term 和 terms 是 包含(contains) 操作,而非 等值(equals) (判断)! 精确相等,如果一定期望得到前面说的那种行为(即整个字段完全相等),最好的方式是增加并索引另一个字段

 

范围

使用 range 查询数字范围的数据

gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)
sql: select * from table where A between a1 and a2;
es :
GET /X/Y/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "range" : {
                    "A" : {
                        "gte" : a1,
                        "lt"  : a2
                    }
                }
            }
        }
    }
}

 

日期范围

range 查询同样可以应用在日期字段上

# 准确的时间范围
"range" : {
    "timestamp" : {
        "gt" : "2019-09-01 00:00:00",
        "lt" : "2019-09-07 00:00:00"
    }
}

# 当前时间一小时内
"range" : {
    "timestamp" : {
        "gt" : "now-1h"
    }
}

# 查询某个指定的区间,跨度一个月
"range" : {
    "timestamp" : {
        "gt" : "2019-09-01 00:00:00",
        "lt" : "2019-09-01 00:00:00||+1M" 
    }
}

 

字符串范围

range 查询同样可以处理字符串字段, 字符串范围可采用 字典顺序(lexicographically) 或字母顺序(alphabetically)。

"range" : {
    "string" : {
        "gte" : "a",
        "lt" :  "b"
    }
}

注意基数,数字和日期字段的索引方式使高效地范围计算成为可能。 但字符串却并非如此,要想对其使用范围过滤,Elasticsearch 实际上是在为范围内的每个词项都执行 term 过滤器,这会比日期或数字的范围过滤慢许多。字符串范围在过滤 低基数(low cardinality) 字段(即只有少量唯一词项)时可以正常工作,但是唯一词项越多,字符串范围的计算会越慢。

 

处理Null值

null, [] (空数组)和 [null] 所有这些都是等价的

存在查询

使用 exists 查询

sql: select * from table where A is NOT NULL;
es: 
GET /X/Y/_search
{
    "query" : {
        "constant_score" : {
            "filter" : {
                "exists" : { "field" : "A" }
            }
        }
    }
}

 

缺失查询

missing 查询本质上与 exists 恰好相反: 它返回某个特定 _无_ 值字段的文档

sql: select * from table where A is NULL;
es:
GET /X/Y/_search
{
    "query" : {
        "constant_score" : {
            "filter": {
                "missing" : { "field" : "A" }
            }
        }
    }
}

 

当 null 的意思是 null
有时候我们需要区分一个字段是没有值,还是它已被显式的设置成了 null 。在之前例子中,我们看到的默认的行为是无法做到这点的;数据被丢失了。不过幸运的是,我们可以选择将显式的 null 值替换成我们指定 占位符(placeholder) 。在为字符串(string)、数字(numeric)、布尔值(Boolean)或日期(date)字段指定映射时,同样可以为之设置 null_value 空值,用以处理显式 null 值的情况。不过即使如此,还是会将一个没有值的字段从倒排索引中排除。


当选择合适的 null_value 空值的时候,需要保证以下几点:
1、它会匹配字段的类型,我们不能为一个 date 日期字段设置字符串类型的 null_value 。
2、它必须与普通值不一样,这可以避免把实际值当成 null 空的情况。

对象上缺失和存在

exists and missing 查询 还可以处理一个对象的内部字段

eg1:
{
   "name" : {
      "first" : "John",
      "last" :  "Smith"
   }
}

eg2:
{
   "name.first" : "John",
   "name.last"  : "Smith"
}

# 存在检查
{
    "exists" : { "field" : "name" }
}
# 等价于
{
    "bool": {
        "should": [
            { "exists": { "field": "name.first" }},
            { "exists": { "field": "name.last" }}
        ]
    }
}
# 只有 name.first 和 name.last 都同时为空的时候才有返回

 

匹配查询

匹配查询 match 是个 核心 查询。无论需要查询什么字段, match 查询都应该会是首选的查询方式。 它是一个高级 全文查询 ,这表示它既能处理全文字段,又能处理精确字段。

单个词查询

GET /X/Y/_search
{
    "query": {
        "match": {
            "title": "QUICK!"
        }
    }
}

Elasticsearch 执行上面这个 match 查询的步骤是:

检查字段类型 
标题 title 字段是一个 string 类型( analyzed )已分析的全文字段,这意味着查询字符串本身也应该被分析。

分析查询字符串 
将查询的字符串 QUICK! 传入标准分析器中,输出的结果是单个项 quick 。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询。

查找匹配文档 
用 term 查询在倒排索引中查找 quick 然后获取一组包含该项的文档,本例的结果是文档:1、2 和 3 。

为每个文档评分 
用 term 查询计算每个文档相关度评分 _score ,这是种将 词频(term frequency,即词 quick 在相关文档的 title 字段中出现的频率)和反向文档频率(inverse document frequency,即词 quick 在所有文档的 title 字段中出现的频率),以及字段的长度(即字段越短相关度越高)相结合的计算方式。

 

多词查询

使用 match 进行多词查询

GET /X/Y/_search
{
    "query": {
        "match": {
            "title": "WORD1 WORD2"
        }
    }
}

 

提高精度

不去匹配 WORD1 OR WORD2 ,而通过匹配 WORD1 AND WORD2 找到所有文档。

GET /X/Y/_search
{
    "query": {
        "match": {
            "title": {      
                "query":    "WORD1 WORD2",
                "operator": "and"
            }
        }
    }
}

 

控制精度

按百分比精度查找,match 查询支持 minimum_should_match 最小匹配参数, 这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量

GET /X/Y/_search
{
  "query": {
    "match": {
      "title": {
        "query": "WORD1 WORD2 WORD2",
        "minimum_should_match": "75%"
      }
    }
  }
}

 

组合查询

与过滤器一样, bool 查询也可以接受 must 、 must_not 和 should 参数下的多个查询语句

# 以下的查询结果返回 A 字段包含词项 WORD1 但不包含 WORD2 的任意文档。目前为止,这与 bool 过滤器的工作方式非常相似,区别就在于两个 should 语句,也就是说:一个文档不必包含 WORD3 或 WORD4 这两个词项,但如果一旦包含,我们就认为它们更相关 
GET /X/Y/_search { "query": { "bool": { "must": { "match": { "A": "WORD1" }}, "must_not": { "match": { "A": "WORD2" }}, "should": [ { "match": { "A": "WORD3" }}, { "match": { "A": "WORD4" }} ] } } }

 

评分计算

bool 查询会为每个文档计算相关度评分 _score , 再将所有匹配的 must 和 should 语句的分数 _score 求和,最后除以 must 和 should 语句的总数。
must_not 语句不会影响评分; 它的作用只是将不相关的文档排除。

 

控制精度

就像能控制 match 查询的精度 一样,我们可以通过 minimum_should_match 参数控制需要匹配的 should 语句的数量, 它既可以是一个绝对的数字,又可以是个百分比

GET /X/Y/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "A": "WORD1" }},
        { "match": { "A": "WORD2"   }},
        { "match": { "A": "WORD3"   }}
      ],
      "minimum_should_match": 2 
    }
  }
}

 

匹配和布尔匹配

多词 match 查询只是简单地将生成的 term 查询包裹 在一个 bool 查询中。如果使用默认的 or 操作符,每个 term 查询都被当作 should 语句,这样就要求必须至少匹配一条语句。以下两个查询是等价的:

{
    "match": { "A": "WORD1 WORD2"}
}
# 等价于
{
  "bool": {
    "should": [
      { "term": { "A": "WORD1" }},
      { "term": { "A": "WORD2"   }}
    ]
  }
}

 

如果使用 and 操作符,所有的 term 查询都被当作 must 语句,所以 所有(all) 语句都必须匹配。以下两个查询是等价的:

{
    "match": {
        "A": {
            "query":    "WORD1 WORD2",
            "operator": "and"
        }
    }
}
#等价于
{
  "bool": {
    "must": [
      { "term": { "A": "WORD1" }},
      { "term": { "A": "WORD2"   }}
    ]
  }
}

 

如果指定参数 minimum_should_match ,它可以通过 bool 查询直接传递,使以下两个查询等价:

{
    "match": {
        "A": {
            "query":"WORD1 WORD2 WORD3",
            "minimum_should_match": "75%"
        }
    }
}
# 等价于
{
  "bool": {
    "should": [
      { "term": { "A": "WORD1" }},
      { "term": { "A": "WORD2"   }},
      { "term": { "A": "WORD3" }}
    ],
    "minimum_should_match": 2 
  }
}

 

查询语句提示权重

假设想要查询关于 “full-text search(全文搜索)” 的文档, 但我们希望为提及 “Elasticsearch” 或 “Lucene” 的文档给予更高的权重 ,这里更高权重是指如果文档中出现 “Elasticsearch” 或 “Lucene” ,它们会比没有的出现这些词的文档获得更高的相关度评分 _score ,也就是说,它们会出现在结果集的更上面。

一个简单的 bool 查询 允许我们写出如下这种非常复杂的逻辑:

GET /_search
{
    "query": {
        "bool": {
            "must": {
                "match": {
                    "content": { 
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [ 
                { "match": { "content": "Elasticsearch" }},
                { "match": { "content": "Lucene"        }}
            ]
        }
    }
}
# content 字段必须包含 full 、 text 和 search 所有三个词。
# 如果 content 字段也包含 Elasticsearch 或 Lucene ,文档会获得更高的评分 _score 。

 

should 语句匹配得越多表示文档的相关度越高。目前为止还挺好。

但是如果我们想让包含 Lucene 的有更高的权重,并且包含 Elasticsearch 的语句比 Lucene 的权重更高,该如何处理?

我们可以通过指定 boost 来控制任何查询语句的相对的权重, boost 的默认值为 1 ,大于 1 会提升一个语句的相对权重。所以下面重写之前的查询:

GET /_search
{
    "query": {
        "bool": {
            "must": {
                "match": {  
                    "content": {
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [
                { "match": {
                    "content": {
                        "query": "Elasticsearch",
                        "boost": 3 
                    }
                }},
                { "match": {
                    "content": {
                        "query": "Lucene",
                        "boost": 2 
                    }
                }}
            ]
        }
    }
}
# 这些语句使用默认的 boost 值 1 。
# Elasticsearch 这条语句更为重要,因为它有最高的 boost 值。
# 这条语句比使用默认值的更重要,但它的重要性不及 Elasticsearch 语句。

 

dis_max查询

不使用 bool 查询,可以使用 dis_max 即分离 最大化查询(Disjunction Max Query) 。分离(Disjunction)的意思是 或(or) ,这与可以把结合(conjunction)理解成 与(and) 相对应。分离最大化查询(Disjunction Max Query)指的是: 将任何与任一查询匹配的文档作为结果返回,但只将最佳匹配的评分作为查询的评分结果返回 :

{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "WORD1 WORD2" }},
                { "match": { "body":  "WORD1 WORD2" }}
            ]
        }
    }
}

 

tie_breaker参数

{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "WORD1 WORD2" }},
                { "match": { "body":  "WORD1 WORD2" }}
            ],
            "tie_breaker": 0.3
        }
    }
}

tie_breaker 参数提供了一种 dis_max 和 bool 之间的折中选择,它的评分方式如下:
1、获得最佳匹配语句的评分 _score 。
2、将其他匹配语句的评分结果与 tie_breaker 相乘。
3、对以上评分求和并规范化。
有了 tie_breaker ,会考虑所有匹配语句,但最佳匹配语句依然占最终结果里的很大一部分。
Tips:tie_breaker 可以是 0 到 1 之间的浮点数,其中 0 代表使用 dis_max 最佳匹配语句的普通逻辑, 1 表示所有匹配语句同等重要。最佳的精确值需要根据数据与查询调试得出,但是合理值应该与零接近(处于 0.1 - 0.4 之间),这样就不会颠覆 dis_max 最佳匹配性质的根本。

 

多匹配查询

multi_match 查询为能在多个字段上反复执行相同查询提供了一种便捷方式。

{
  "dis_max": {
    "queries":  [
      {
        "match": {
          "title": {
            "query": "Quick brown fox",
            "minimum_should_match": "30%"
          }
        }
      },
      {
        "match": {
          "body": {
            "query": "Quick brown fox",
            "minimum_should_match": "30%"
          }
        }
      },
    ],
    "tie_breaker": 0.3
  }
}

# 等价于

{
    "multi_match": {
        "query":                "Quick brown fox",
        "type":                 "best_fields", 
        "fields":               [ "title", "body" ],
        "tie_breaker":          0.3,
        "minimum_should_match": "30%" 
    }
}

 

模糊匹配

字段名称可以用模糊匹配的方式给出:任何与模糊模式正则匹配的字段都会被包括在搜索条件中, 例如可以使用以下方式同时匹配 book_title 、 chapter_title 和 section_title (书名、章名、节名)这三个字段:

{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": "*_title"
    }
}

 

提升单个字段的权重

可以使用 ^ 字符语法为单个字段提升权重,在字段名称的末尾添加 ^boost , 其中 boost 是一个浮点数:

{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": [ "*_title", "chapter_title^2" ] 
    }
}
# chapter_title 这个字段的 boost 值为 2 ,而其他两个字段 book_title 和 section_title 字段的默认 boost 值为 1 。

 

短语匹配

就像 match 查询对于标准全文检索是一种最常用的查询一样,当你想找到彼此邻近搜索词的查询方法时,就会想到 match_phrase 查询 。

GET /X/Y/_search
{
    "query": {
        "match_phrase": {
            "title": "quick brown fox"
        }
    }
}
# 等价于
"match": {
    "title": {
        "query": "quick brown fox",
        "type":  "phrase"
    }
}

类似 match 查询, match_phrase 查询首先将查询字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含 全部 搜索词项,且 位置 与搜索词项相同的文档。 比如对于 quick fox 的短语搜索可能不会匹配到任何文档,因为没有文档包含的 quick 词之后紧跟着 fox 。

 

混合

精确短语匹配 或许是过于严格了。也许我们想要包含 “quick brown fox” 的文档也能够匹配 “quick fox,” , 尽管情形不完全相同。
我们能够通过使用 slop 参数将灵活度引入短语匹配中:

GET /X/Y/_search
{
    "query": {
        "match_phrase": {
            "title": {
                "query": "quick fox",
                "slop":  1
            }
        }
    }
}
# slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配 。 相隔多远的意思是为了让查询和文档匹配你需要移动词条多少次

 

前缀查询 

为了找到所有以 W1 开始的数据,可以使用简单的 prefix 查询:

GET /X/Y/_search
{
    "query": {
        "prefix": {
            "column": "W1"
        }
    }
}

 

通配符正则查询

与 prefix 前缀查询的特性类似, wildcard 通配符查询也是一种底层基于词的查询, 与前缀查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符查询: ? 匹配任意字符, * 匹配 0 或多个字符。

GET /X/Y/_search
{
    "query": {
        "wildcard": {
            "column": "W?F*HW" 
        }
    }
}

 

 

参考:https://www.elastic.co/guide/cn/elasticsearch/guide/cn/index.html

可视化工具推荐:Kibana

posted @ 2019-07-30 17:04  凌雨尘  阅读(2166)  评论(0编辑  收藏  举报