• 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

  • 相关阅读:
    JavaScript 学习36.jQuery 获取和修改HTML 上海
    JavaScript 学习39.jQuery Ajax请求 上海
    低代码和人工智能助力疫情期间抗原自测信息自动化收集和处理
    使用Kafka时一定要注意防止消费速度过慢触发rebalance而导致的重复消费
    Cogview2:更快更好的文生图分层Transformer模型
    android root 更改system/app内容
    极钛星华pro1T智能话机(点评管家/美味不用等)型号p1A32 开启adb root等
    go CRUD
    delphi restfulWiRL
    delphi面向服务开发解决方案
  • 原文地址:https://www.cnblogs.com/lyc94620/p/11271259.html
Copyright © 2020-2023  润新知