zoukankan      html  css  js  c++  java
  • Elasticsearch URI search 查询语法整理

    Elasticsearch URI search

    一、请求体查询与空查询

    1. 请求体查询(request body search)

    简单查询语句(lite)是一种有效的命令行adhoc查询。但是,如果你想要善用搜索,你必须使用请求体查询(request body search) API。之所以这么称呼,是因为大多数的参数以JSON格式所容纳而非查询字符串。

    请求体查询(以下简称查询),并不仅仅用于处理查询,而且还可以高亮返回结果中的片段,并且给出帮助你的用户找寻最好结果的相关数据建议。

    2. 空查询

    我们以最简单的search API开始,空查询将会返回索引中所有的文档。

    GET /_search
    {}
    

    同字符串查询一样,你可以查询一个,多个或_all索引(indices)或类型(types):

    GET /index_2014*/type1,typ2/_search
    {}
    

    你可以使用from及size参数进行分页:

    GET /_search
    {
       "from" : 30,
       "size" : 10
    }
    

    携带内容的GET请求?

    任何一种语言(特别是js)的HTTP库都不允许GET请求中携带交互数据。事实上,有些用户很惊讶GET请求中居然会允许携带交互数据。
    真实情况是,http://tools.ietf.org/html/rfc7231#page-24[RFC 7231], 一份规定HTTP语义及内容的RFC中并未规定 GET 请求中允许携带交互数据! 所以,有些HTTP服务允许这种行为,而另一些(特别是缓存代理),则不允许这种行为。

    Elasticsearch的作者们倾向于使用GET提交查询请求,因为他们觉得这个词相比POST来说,能更好的描述这种行为。然而,因为携带交互数据的GET请求并不被广泛支持,所以search API同样支持POST请求,类似于这样:

    POST /_search
    {
      "from" : 30,
      "size" : 10
    }
    

    这个原理同样应用于其他携带交互数据的GET API请求中。

    相对于神秘的查询字符串方法,请求体查询允许我们使用结构化查询Query DSL(Query Domain Specific Language)

    二、结构化查询

    bool联合查询: must, should, must_not

    must: 文档必须完全匹配条件,选择多个即 且 的意思;
    should: should下面会带一个以上的条件,至少满足一个条件,这个文档就符合should,选择多个即 且 的意思;
    must_not: 文档必须不匹配条件,选择多个即 且 的意思;

    如果我们想要请求"content中带宝马,但是tag中不带宝马"这样类似的需求,就需要用到bool联合查询。

    样例

    全文检索,模糊匹配,message.keyword 包含“Error”,项目名称不以“boe”开头的数据。
    此处我们需要使用 bool 查询:

    GET awsbpm_prod_log-2019.08.20/_search
    {
        "query":{
            "bool":{
                "must": [
                    {
                        "match_all":{
    
                        }
                    },
                    {
                        "wildcard":{
                            "message.keyword":"*Error*"
                        }
                    }
                ],
                "must_not":[
    
                ],
                "should":[
    
                ]
            }
        },
        "from":11,
        "size":20,
        "sort":[
    
        ],
        "aggs":{
    
        }
    }
    

    高级检索语法:term, wildcard, prefix, fuzzy, range, query_string, text, missing

    term:严格匹配条件,所查询的字段内容要与填入查询框搜索值一致;
    wildcard:通配符查询,* 表示全匹配,? 表示单一匹配,etc: aaa* 或者 a?b;
    prefix:前缀匹配,搜索框如果输入aa,那么可能匹配到的字段值为 aab,aavb等;
    fuzzy min_similarity:弹性模糊匹配,有两个搜索框,第一个搜索框为搜索匹配值,会自动纠错,比如输入 ggjk,那么可能会匹配到ggjo,第二个框为最小相似度,采用的算法是Damerau-Levenshtein(最佳字符串对齐)算法,不建议填写这个框,我到发稿前也是被搞的头皮发麻,等我完全吃透再更新;
    fuzzy max_expansions :弹性模糊匹配,有两个搜索框,第一个搜索框为搜索匹配值,会自动纠错,比如输入 ggjk,那么可能会匹配到ggjo,第二个框是最大扩展匹配数,比如是1,那么ggjk只会随机模糊匹配到一种可能结果,即使它会出现2种或者更加多,也只会搜索一种;
    range:范围查询,gt为大于,gte为大于等于,lt小于,lte小于等于,所搜索的字段值在两个搜索框标识数值之间;
    query_string:字符片段查询,如果是数字,则严格匹配数字,如果是字符串,则按照自身或者分片词匹配;
    text:分片词查询,等确定后更新;
    missing:查询没有定义该字段或者该字段值为null的数据。

    1. term query - 索引词检索

    (1) term query - 不分词检索

    term query: 把检索串当作一个整体来执行检索, 即不会对检索串分词.
    
    term是完全匹配检索, 要用在不分词的字段上, 如果某个field在映射中被分词了, term检索将不起作用.
    所以, 不分词的field, 要在mapping中设置为不分词.
    
    —— ES 5.x之后, 为每个text类型的字段新增了名为keyword的子字段, 是不分词的, 默认保留256个字符.
    
    —— 可以使用keyword字段进行term检索. 
    示例:
    
    GET shop/_search
    {
    	"query": {
    		"term": {
    		"name.keyword": "Java编程思想"
    		}
    	}
    }
    

    (2) terms query - in检索

    terms, 相当于多个term检索, 类似于SQL中in关键字的用法, 即在某些给定的数据中检索:

    GET shop/_search
    {
    	"query": {
    		"terms": {
    			"name.keyword": [
    				"Java编程思想", "Java并发编程的艺术"
    				]
    		}
    	}
    }
    

    2. prefix query - 前缀检索

    prefix query, 就是前缀检索. 比如商品name中有多个以"Java"开头的document, 检索前缀"Java"时就能检索到所有以"Java"开头的文档.

    —— 扫描所有倒排索引, 性能较差.

    GET shop/_search
    {
    	"query": {
    		"prefix": { "name": "java" }
    	}
    }
    

    3. wildcard query - 通配符检索

    扫描所有倒排索引, 性能较差.

    GET shop/_search
    {
        "query": {
            "wildcard": { "name": "ja*" }
        }
    }
    

    4. regexp query - 正则检索

    扫描所有倒排索引, 性能较差.

    GET shop/_search
    {
        "query": {
            "regexp": { "name": "jav[a-z]*" }
        }
    }
    

    5. fuzzy query - 纠错检索

    fuzziness的默认值是2 —— 表示最多可以纠错两次.

    说明: fuzziness的值太大, 将削弱检索条件的作用, 也就是说纠错次数太多, 就会导致限定检索结果的检索条件被改变, 失去了限定作用.

    示例: 检索name中包含"Java"的文档, Java中缺失了一个字母a:

    GET shop/_search
    {
        "query": {
            "match": { 
                "name": {
                    "query": "Jav", 
                    "fuzziness": 1, 
                    "operator": "and"
                }
            }
        }
    }
    

    6. boost评分权重 - 控制文档的优先级别

    通过boost参数, 令满足某个条件的文档的得分更高, 从而使得其排名更靠前.

    GET shop/_search
    {
        "query": {
            "bool": {
                "must": [
                    { "match": { "name": "编程思想"} }
                ], 
                "should": [
                    { 
                       "match": { 
                            "name": {
                                "query": "艺术", 
                                "boost": 2        // 提升评分权重
                            } 
                        }
                    }
                ]
            }
        }
    }
    

    7. dis_max的用法 - best fields策略

    (1) dis_max的提出
    如果我们希望检索结果中 (检索串被分词后的) 关键字匹配越多, 这样的文档就越靠前, 而不是多个子检索中匹配少量分词的文档靠前.

    ⇒ 此时可以使用dis_max和tie_breaker.

    tie_breaker的值介于0~1之间, Elasticsearch将 bool检索的分数 * tie_breaker的结果与dis_max的最高分进行比较, 除了取dis_max的最高分以外, 还会考虑其他的检索结果的分数.

    (2) 使用示例
    为了增加精准度, 常用的是配合boost、minimum_should_match等参数控制检索结果.

    GET shop/_search
    {
        "query": {
            "dis_max": {
                "queries": [
                    { "match": { "name": "虚拟机" } },
                    { "match": { "desc": "经典" } }
                ],
                "tie_breaker": 0.2      // 对同时满足的文档的分值进行提升
            }
        }
    }
    
    GET shop/_search
    {
        "query": {
            "dis_max": {
                "queries": [
                    { 
                        "match": { 
                            "name": {
                                "query": "虚拟机",
                                "minimum_should_match": "50%",
                                "boost": 2
                            }
                        }
                    },
                    {
                        "match": {
                            "desc": {
                                "query": "经典",
                                "minimum_should_match": "50%", 
                                "boost": 3
                            }
                        }
                    }
                ],
                "tie_breaker": 0.3
            }
        }
    }
    

    三、复杂检索的使用范例

    1. 多条件过滤 - 包含

    检索出版时间在2012-07之后, 且至少满足下述条件中一个的文档:

    a. 名称(name)中包含"并发";

    b. 描述(desc)中包含"java";

    c. 出版社(publisher)名称中不包含"电子".

    GET shop/_search
    {
        "query": {
            "bool": {
                "filter": {                 // 按时间过滤
                    "range": {
                        "date": {"gte": "2012-07"}
                    }
                },
                "should": [                 // 可匹配, 可不匹配
                    {
                        "match": { "name": "并发" }
                    },
                    {
                        "bool": {
                            "must": {       // 必须匹配
                                "match": { "desc": "java" }
                            },
                            "must_not": {   // 不能匹配
                                "match": { "publisher": "电子" }
                            }
                        }
                    }
                ],
                "minimum_should_match": 1   // 至少满足should中的一个条件
            }
        }, 
        // 自定义排序
        "sort": [
            { "price": { "order": "desc" } }
        ]
    }
    

    注意: 排序的字段最好是数字, 或日期, 因为字符串字段会被分词, ES会通过分词后的某个词去排序, 结果难以预测.

    2. 多条件拼接 - 包含+范围+排序

    匹配检索: name中包含"java"却不包含"虚拟机";
    范围检索: 价格大于50、小于80;
    结果排序: 按照价格升序排序.

    GET shop/_search
    {
        "query": {
            "bool": {
                "must": {                       // 必须匹配
                    "match": { "name": "java" }
                }, 
                "must_not": {                   // 必须不匹配
                    "match": { "name": "虚拟机" }
                },
                "filter": {
                    "range": {
                        "price": {
                            "gte": 40,
                            "lte": 80,
                            "boost": 2.0    // 设置得分的权重值(提升值), 默认是1.0
                        }
                    }
                }
            }
        }
    }
    

    关于范围检索的使用, 请参考下篇文章: ES 22 - Elasticsearch对数值或日期类型进行范围检索

    3. 定制检索结果的排序规则

    (1) 默认排序规则:

    ES默认是按检索结果的分值(_score)降序排列的.

    某些情况下, 可能存在无实际意义的_score, 比如filter时所有_score的值都相同:

    GET website/_search
    {
        "query": {
            "bool": {
                "filter": {
                    "term": {
                        "author_id": 5520   // 此时所有符合条件的_score都为0
                    }
                }
            }
        }
    }
    

    // 或通过constant_score过滤:

    GET website/_search
    {
        "query": {
            "constant_score": {
                "filter": {
                    "term": {
                        "author_id": 5520   // 此时所有符合条件的_score都为1
                    }
                }
            }
        }
    }
    

    (2) 定制排序规则:

    GET website/_search
    {
        "query": {
            "constant_score": {
                "filter": {
                    "term": {
                        "author_id": 5520
                    }
                }
            }
        }, 
        "sort": [
            {
                "post_date": { "order": "asc" }
            }
        ]
    }
    

    四、Elasticsearch filter和query的不同

    1. query和filter的本质区别?

    query关注点:此文档与此查询子句的匹配程度如何?

    filter关注点:此文档和查询子句匹配吗?

    2、Query检索细化关注点

    1)是否包含?

    确定文档是否应该成为结果的一部分.

    2)相关度得分多少?

    除了确定文档是否匹配外,查询子句还计算了表示文档与其他文档相比匹配程度的_score。

    3)得分越高,相关度越高。

    更相关的文件,在搜索排名更高。

    典型应用场景:

    1)全文检索——这种相关性的概念非常适合全文搜索,因为很少有完全“正确”的答案。

    举例如下:

    文档中存在字段hotel_name:“上海浦东香格里拉酒店”

    IK实际分词结果如下:
    上海浦东,上海,浦东,香格里拉,格里,里拉,酒店。

    也就是说,搜索以上关键词都能搜到:hotel_name:“上海浦东香格里拉酒店”的酒店。这些都是“相关”的。

    但是搜索:“香格里” 是搜索不到结果的。

    2)包含单词“run”, 但也匹配”runs”, “running”, “jog”或者”sprint”。(都是奔跑的意思)

    3. filter过滤细化关注点

    1)是否包含?

    确定是否包含在检索结果中,回答只有“是”或“否”。

    2)不涉及评分。

    在搜索中没有额外的相关度排名。

    3)针对结构化数据。

    适用于完全精确匹配,范围检索。

    参见官网举例:
    以下场景适用于filter过滤检索:

    举例1:时间戳timestamp 是否在2015至2016年范围内?

    举例2:状态字段status 是否设置为“published”?

    4)更快。

    只确定是否包括结果中,不需要考虑得分。

    为什么会更快?——经常使用的过滤器将被Elasticsearch自动缓存,以提高性能。

    4. query和filter的性能不同

    过滤查询(filter)是对集合包含/排除的简单检查,这使得它们计算速度非常快。 当至少有一个过滤查询是“稀疏”(仅有少量匹配的文档)时,可以利用各种优化,并且可以将缓存经常使用的filter过滤查询缓存在内存中以加快访问速度。

    对比之下,query检索(评分查询)不仅要查找匹配的文档,还要计算每个文档的相关程度,这通常会使其比非评分文档更复杂。 另外,查询结果不可缓存。

    由于倒排索引,只有几个文档匹配的简单评分查询(query检索)可能会比跨越数百万个文档的过滤器(filter过滤)表现得更好。 但是,一般来说,fiter过滤的性能将胜过评分查询(query检索)。

    过滤(filter)的目标是减少必须由评分查询(query)检查的文档数量。

    5. filter过滤怎么缓存呢?

    Elasticsearch将创建一个文档匹配过滤器的位集bitset(如果文档匹配则为1,否则为0)。 随后用相同的过滤器执行查询将重用此信息。

    每当添加或更新新文档时,位集bitset也会更新。

    6. 使用场景

    全文检索以及任何使用相关性评分的场景使用query检索。

    除此之外的其他使用filter过滤器过滤。

    7. query和filter实战

    ebay在Elasticsearch使用经验中总结到:

    Use filter context instead of query context if possible.

    即:如果可能,请使用filter过滤器上下文而不是query查询上下文。

    查询query和过滤器filter已合并(在ES1.X版本是分开的,存在filtered检索类型)。

    ES高版本(2.X/5.X/6.x以后),任何查询子句都可以在“查询上下文query”中用作查询,并在“过滤器上下文filter”中用作过滤器。

    举例:

    GET /_search
    {
      "query": { 
        "bool": { 
          "must": [
            { "match": { "title":   "Search"        }}, 
            { "match": { "content": "Elasticsearch" }}  
          ],
          "filter": [ 
            { "term":  { "status": "published" }}, 
            { "range": { "publish_date": { "gte": "2015-01-01" }}} 
          ]
        }
      }
    }
    

    参考资料:

    Elasticsearch的高级检索语法 (包括term、prefix、wildcard、fuzzy、boost等)
    https://www.cnblogs.com/shoufeng/p/11103913.html
    Elasticsearch URI search
    https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
    query-filter-context
    https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html#relevance-scores
    Elasticsearch filter和query的不同
    https://blog.csdn.net/laoyang360/article/details/80468757
    queries_and_filters
    https://www.elastic.co/guide/en/elasticsearch/guide/master/_queries_and_filters.html
    How to monitor Elasticsearch performance
    https://www.datadoghq.com/blog/monitor-elasticsearch-performance-metrics/
    Elasticsearch Performance Tuning Practice at eBay
    https://tech.ebayinc.com/engineering/elasticsearch-performance-tuning-practice-at-ebay/

  • 相关阅读:
    java学生成绩管理系统
    7.19至7.25第八周学习情况
    8.12至8.18第七周学习情况
    8.5至8.11第六周学习情况
    7.29至8.4第五周学习情况
    《大道至简》读后感
    7.22至7.28第四周学习情况
    7.15至7.21第三周学习情况
    LeetCode 第三题:Longest Substring Without Repeating Characters
    哈希表(散列表)
  • 原文地址:https://www.cnblogs.com/doraman/p/11414804.html
Copyright © 2011-2022 走看看