前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch使用:Search 概括

Elasticsearch使用:Search 概括

原创
作者头像
HLee
修改2021-10-21 09:47:19
1.1K0
修改2021-10-21 09:47:19
举报
文章被收录于专栏:房东的猫

简介

在 Elasticsearch 中的搜索中,有两类搜索:queries和aggregations。

它们之间的区别在于:query 可以帮我们进行全文搜索,而 aggregation 可以帮我们对数据进行统计及分析。我们有时也可以结合 query 及 aggregation 一起使用,比如我们可以先对文档进行搜索然后在进行聚合 :

代码语言:javascript
复制
GET blogs/_search
{
  "query": {
    "match": {
      "title": "community"
    }
  },
  "aggregations": {
    "top_authors": {
      "terms": {
        "field": "author"
      }
    }
  }
}

结构化检索

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

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

exists

代码语言:javascript
复制
GET twitter/_search
{
  "query": {
    "exists": {
      "field": "city"
    }
  }
}

ids

代码语言:javascript
复制
POST sphinx-doctor/_mget
{
   "ids" : [ "9", "10" ]
}

位置查询

Elasticsearch 最厉害的是位置查询。这在很多的关系数据库里并没有。我们举一个简单的例子:

代码语言:javascript
复制
GET twitter/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "北京"
          }
        }
      ]
    }
  },
  "post_filter": {
    "geo_distance": {
      "distance": "3km",
      "location": {
        "lat": 39.920086,
        "lon": 116.454182
      }
    }
  }
}

下面,我们找出在 5 公里以内的所有位置信息,并按照远近大小进行排序:

代码语言:javascript
复制
GET twitter/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "北京"
          }
        }
      ]
    }
  },
  "post_filter": {
    "geo_distance": {
      "distance": "5km",
      "location": {
        "lat": 39.920086,
        "lon": 116.454182
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": "39.920086,116.454182",
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

GET twitter/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "address": "北京"
        }
      },
      "filter": {
        "geo_distance": {
          "distance": "5km",
          "location": {
            "lat": 39.920086,
            "lon": 116.454182
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": "39.920086,116.454182",
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

全文检索

全文搜索(full-text search) :怎样在全文字段中搜索到最相关的文档。

fuzzy

代码语言:javascript
复制
{
  "query": {
    "fuzzy": {
      "hospitalcity.keyword": {
        "value": "北京"
      }
    }
  }
}

term

代码语言:javascript
复制
{
  "query": {
    "fuzzy": {
      "hospitalcity.keyword": {
        "value": "北京"
      }
    }
  }
}

match

代码语言:javascript
复制
{
    "query": {
        "match": {
            "title": "QUICK!"
        }
    }
}

query_string

代码语言:javascript
复制
{
  "query": {
    "query_string": {
      "default_field": "hospitalcity",
      "query": "北京"
    }
  }
}

多字段搜索

通常我们需要用相同或不同的字符串查询一个或多个字段,也就是说,需要对多个查询语句以及它们相关度评分进行合理的合并。

最佳字段

代码语言:javascript
复制
{
  "query": {
    "dis_max": {
      "boost": 1.2,
      "queries": [
        {
          "match": {
            "FIELD": "TEXT"
          }
        },
        {
          "match": {
            "FIELD": "TEXT"
          }
        }
      ]
    }
  }
}


{
  "query": {
    "multi_match": {
      "query": "北京",
      "fields": [
        "hospitalprovince^3",
        "hospitalcity"
      ],
      "type": "best_fields",
      "tie_breaker": 0.3,
      "minimum_should_match": "80%"
    }
  }
}

多数字段

代码语言:javascript
复制
{
    "query": {
        "bool": {
            "should": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}


{
  "query": {
    "dis_max": {
      "tie_breaker": 0.7,
      "boost": 1.2,
      "queries": [
        {
          "match": {
            "FIELD": "TEXT"
          }
        },
        {
          "match": {
            "FIELD": "TEXT"
          }
        }
      ]
    }
  }
}


{
   "query": {
        "multi_match": {
            "query":  "jumping rabbits",
            "type":   "most_fields",   #我们希望将所有匹配字段的评分合并起来,所以使用 most_fields 类型。这让 multi_match 查询用 bool 查询将两个字段语句包在里面,而不是使用 dis_max 查询。 
            "fields": [ "title", "title.std" ]
        }
    }
}

跨字段

代码语言:javascript
复制
{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "cross_fields",
            "operator":    "and",   #所有词都是必须的。 
            "fields":      [ "first_name", "last_name" ]
        }
    }
}

词中心式:
+(first_name:peter last_name:peter)
+(first_name:smith last_name:smith)

字段中心式:
(+first_name:peter +first_name:smith)
(+last_name:peter  +last_name:smith)

换句话说,它会同时在 first_namelast_name 两个字段中查找 smith 的 IDF ,然后用两者的最小值作为两个字段的 IDF 。

采用 cross_fields 查询与 自定义 _all 字段 相比,其中一个优势就是它可以在搜索时为单个字段提升权重。

短语检索

当你想找到彼此邻近搜索词的查询方法时,就会想到 match_phrase 查询 。

代码语言:javascript
复制
Es低版本支持:
{
  "query": {
    "match": {
      "title": {
        "query": "quick brown fox",
        "type": "phrase"
      }
    }
  }
}


{
  "query": {
    "bool": {
      "must": {
        "match": {   #must 子句从结果集中包含或者排除文档
          "title": {
            "query":                "quick brown fox",
            "minimum_should_match": "30%"
          }
        }
      },
      "should": {
        "match_phrase": {   #should 子句增加了匹配到文档的相关度评分。
          "title": {
            "query": "quick brown fox",
            "slop":  50
          }
        }
      }
    }
  }
}


重新评分:
{
    "query": {
        "match": {   #match 查询决定哪些文档将包含在最终结果集中,并通过 TF/IDF 排序。 
            "title": {
                "query":                "quick brown fox",
                "minimum_should_match": "30%"
            }
        }
    },
    "rescore": {
        "window_size": 50,   #window_size 是每一分片进行重新评分的顶部文档数量。
        "query": {      #目前唯一支持的重新打分算法就是另一个查询,但是以后会有计划增加更多的算法。      
            "rescore_query": {
                "match_phrase": {
                    "title": {
                        "query": "quick brown fox",
                        "slop":  50
                    }
                }
            }
        }
    }
}

部分检索

部分匹配 允许用户指定查找词的一部分并找出所有包含这部分片段的词。prefix 、 wildcard 和 regexp 查询是基于词操作的,如果用它们来查询 analyzed 字段,它们会检查字段里面的每个词,而不是将字段作为整体来处理。

prefix 前缀

prefix 查询是一个词级别的底层的查询,它不会在搜索之前分析查询字符串,它假定传入前缀就正是要查找的前缀。

默认状态下, prefix 查询不做相关度评分计算,它只是将所有匹配的文档返回,并为每条结果赋予评分值 1 。它的行为更像是过滤器而不是查询。 prefix 查询和 prefix 过滤器这两者实际的区别就是过滤器是可以被缓存的,而查询不行。

代码语言:javascript
复制
{
    "query": {
        "prefix": {
            "postcode": "W1"
        }
    }
}

{
    "match_phrase_prefix" : {
        "brand" : {
            "query": "walker johnnie bl", 
            "max_expansions": 50,
            "slop":  10  #尽管词语的顺序不正确,查询仍然能匹配,因为我们为它设置了足够高的 slop 值使匹配时的词序有更大的灵活性。 
        }
    }
}

wildcard 通配符

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

代码语言:javascript
复制
{
    "query": {
        "wildcard": {
            "postcode": "W?F*HW"   #? 匹配 1 和 2 , * 与空格及 7 和 8 匹配。 
        }
    }
}

regexp 正则式

代码语言:javascript
复制
{
    "query": {
        "regexp": {
            "postcode": "W[0-9].+"   #这个正则表达式要求词必须以 W 开头,紧跟 0 至 9 之间的任何一个数字,然后接一或多个其他字符。 
        }
    }
}

控制相关度

Doc相关度评分

Index相关度评分

当在多个索引中搜索时, 可以使用参数 indices_boost 来提升整个索引的权重。在下面例子中,当要为最近索引的文档分配更高权重时,可以这么做:

代码语言:javascript
复制
GET /docs_2014_*/_search   #这个多索引查询涵盖了所有以字符串 docs_2014_ 开始的索引。 
{
  "indices_boost": {   #其中,索引 docs_2014_10 中的所有文件的权重是 3 ,索引 docs_2014_09 中是 2 ,其他所有匹配的索引权重为默认值 1 。 
    "docs_2014_10": 3,
    "docs_2014_09": 2
  },
  "query": {
    "match": {
      "text": "quick brown fox"
    }
  }
}

相关度检索评分

boosting

它接受 positivenegative 查询。只有那些匹配 positive 查询的文档罗列出来,对于那些同时还匹配 negative 查询的文档将通过文档的原始 _scorenegative_boost 相乘的方式降级后的结果。

为了达到效果, negative_boost 的值必须小于 1.0 。在这个示例中,所有包含负向词的文档评分 _score 都会减半。

代码语言:javascript
复制
GET /_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "text": "apple"
        }
      },
      "negative": {
        "match": {
          "text": "pie tart fruit crumble tree"
        }
      },
      "negative_boost": 0.5
    }
  }
}

constant_score

有时候我们根本不关心 TF/IDF , 只想知道一个词是否在某个字段中出现过。

constant_score 查询中,它可以包含查询或过滤,为任意一个匹配的文档指定评分 1 ,忽略 TF/IDF 信息。

代码语言:javascript
复制
GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "constant_score": {
          "query": { "match": { "description": "wifi" }}
        }},
        { "constant_score": {
          "query": { "match": { "description": "garden" }}
        }},
        { "constant_score": {
          "boost":   2   #pool 语句的权重提升值为 2 ,而其他的语句为 1 。 
          "query": { "match": { "description": "pool" }}
        }}
      ]
    }
  }
}

function_score

function_score 查询 是用来控制评分过程的终极武器,它允许为每个与主查询匹配的文档应用一个函数, 以达到改变甚至完全替换原始查询评分 _score 的目的。

代码语言:javascript
复制
GET /blogposts/post/_search
{
  "query": {
    "function_score": {   #function_score 查询将主查询和函数包括在内。 
      "query": {   #主查询优先执行。
        "multi_match": {
          "query":    "popularity",
          "fields": [ "title", "content" ]
        }
      },
      "field_value_factor": {   #field_value_factor 函数会被应用到每个与主 query 匹配的文档。 
        1."field": "votes"   #每个文档的 votes 字段都 必须 有值供 function_score 计算。如果 没有 文档的 votes 字段有值,那么就 必须 使用 missing 属性 提供的默认值来进行评分计算。 
        2."modifier": "log1p"   #modifier 为 log1p 。
        3."factor":   2   #双倍效果。factor 值大于 1 会提升效果, factor 值小于 1 会降低效果
      },
      4."boost_mode": "sum" ,  #将函数计算结果值累加到评分 _score 。
      5."max_boost":  1.5   #无论 field_value_factor 函数的结果如何,最终结果都不会大于 1.5 。 
    }
  }
}

1.new_score = old_score * number_of_votes
2.new_score = old_score * log(1 + number_of_votes)
3.new_score = old_score * log(1 + factor * number_of_votes)
4.new_score = old_score + log(1 + 0.1 * number_of_votes)

到目前为止,我们展现的都是为所有文档应用单个函数的使用方式,现在会用过滤器将结果划分为多个子集(每个特性一个过滤器),并为每个子集使用不同的函数。

代码语言:javascript
复制
GET /_search
{
  "query": {
    "function_score": {
      "filter": {  #function_score 查询有个 filter 过滤器而不是 query 查询。 
        "term": { "city": "Barcelona" }
      },
      "functions": [   #functions 关键字存储着一个将被应用的函数列表。 
        {
          "filter": { "term": { "features": "wifi" }},   #函数会被应用于和 filter 过滤器(可选的)匹配的文档。
          "weight": 1
        },
        {
          "filter": { "term": { "features": "garden" }},   #函数会被应用于和 filter 过滤器(可选的)匹配的文档。
          "weight": 1
        },
        {
          "filter": { "term": { "features": "pool" }},   #函数会被应用于和 filter 过滤器(可选的)匹配的文档。
          "weight": 2   #pool 比其他特性更重要,所以它有更高 weight 。 
        },
        {
          "random_score": {   #random_score 语句没有任何过滤器 filter ,所以会被应用到所有文档。 
            "seed":  "the users session id"   #将用户的会话 ID 作为种子 seed ,让该用户的随机始终保持一致,相同的种子 seed 会产生相同的随机结果。 
          }
        }
      ],
      "score_mode": "sum",   #score_mode 指定各个函数的值进行组合运算的方式。
    }
  }
}

function_score 查询会提供一组 衰减函数(decay functions) , 让我们有能力在两个滑动标准,如地点和价格,之间权衡。

代码语言:javascript
复制
GET /_search
{
  "query": {
    "function_score": {
      "functions": [
        {
          "gauss": {
            "location": {   #location 字段以地理坐标点 geo_point 映射。 
              "origin": { "lat": 51.5, "lon": 0.12 },
              "offset": "2km",
              "scale":  "3km"
            }
          }
        },
        {
          "gauss": {
            "price": {   #price 字段是数值。 
              "origin": "50",   #参见 理解价格语句 ,理解 origin 为什么是 50 而不是 100 。
              "offset": "50",
              "scale":  "20"
            }
          },
          "weight": 2   #price 语句是 location 语句权重的两倍。
        },
        {
        "script_score": {
          "params": {   #将这些变量作为参数 params 传递,我们可以查询时动态改变脚本无须重新编译。
            "threshold": 80,
            "discount": 0.1,
            "target": 10
          },
          "script": "price  = doc['price'].value; margin = doc['margin'].value;
          if (price < threshold) { return price * margin / target };
          return price * (1 - discount) * margin / target;"   #JSON 不能接受内嵌的换行符,脚本中的换行符可以用 \n 或 ; 符号替代。 
          }
        }
      ]
    }
  }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 结构化检索
    • exists
      • ids
        • 位置查询
        • 全文检索
          • fuzzy
            • term
              • match
                • query_string
                • 多字段搜索
                  • 最佳字段
                    • 多数字段
                      • 跨字段
                      • 短语检索
                      • 部分检索
                        • prefix 前缀
                          • wildcard 通配符
                            • regexp 正则式
                            • 控制相关度
                              • Doc相关度评分
                                • Index相关度评分
                                  • 相关度检索评分
                                    • boosting
                                    • constant_score
                                    • function_score
                                相关产品与服务
                                Elasticsearch Service
                                腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档