美文网首页
ES 深入理解搜索

ES 深入理解搜索

作者: 鸿雁长飞光不度 | 来源:发表于2020-02-04 23:07 被阅读0次

    1.基于Term的查询

    Term是表达语义的最小单位,搜索和自然语言处理都用Term处理。

    • Term级别的查询:Term查询、范围查询、存在性查询、前缀查询、通配符查询。
    • 在ES里面对于Term查询,输入不做分词。将输入当成一个整体,在倒排索引里面查找准确的词。然后根据公式对文档进行算分。
    • 可以通过Constant Score,避免算分,并利用缓存提高性能。

    案例

    POST /products/_bulk
    {"index":{"_id":1}}
    {"product_id":"ABC-DEF","desc":"iPhone"}
    {"index":{"_id":2}}
    {"product_id":"ABC-bba","desc":"iPad"}
    
    POST /products/_search
    {
      "query": {
        "term": {
          "desc": {
            "value": "iPhone"//查不到,"iphone"可以,
          }
        }
      }
    }
    POST /products/_search
    {
      "query": {
        "term": {
          "product_id.keyword": {
            "value": "ABC-bba"
          }
        }
      }
    }
    忽略计算评分
     {
      "query": {
        "constant_score": {
          "filter": {
            "term": {
              "product_id.keyword": "ABC-bba"
            }
          }
        }
      }
    }
    

    2.基于全文的查询

    可以通过match、match phrase、query string这些类的查询实现。

    特点:

    • 索引和搜索时都会进行分词,查询字符串先传递一个合适的分词器,然后生成可供查询的列表。
    • 查询,先对输入分词,对每个单词逐个底层查询,最终合并结果,并计算分数。

    详细内容见:https://www.jianshu.com/p/8e70f80cca80

    3.结构化搜索

    3.1 结构化数据

    • 布尔类型和数字类型是结构化的
    • 文本也可以是结构化的
      • 彩色笔可以有离散的颜色结合。
      • 博客可能被标记了标签。
      • 电商网站上的商品的标识符,严格规定结构化的格式

    3.2 ES的结构化搜索

    • 布尔、时间、日期或者数字这类结构化数据:有精确的格式,可以进行逻辑操作。包括比较数字或者范围比较,判断两个值大小。
    • 结构化的文本可以做精确匹配或者部分匹配:Term查询/Prefix前缀查询。
    • 结构化结果只有是或者否两个值,可以根据场景需要决定是否打分。

    范围查询案例:

    POST products/_search
    {
      "query": {
        "constant_score": {
          "filter": {
            "range": {
              "price": {
                "gte": 10,
                "lte": 20
              }
            }
          },
          "boost": 1.2
        }
      }
    }
    

    4.相关性算分

    搜索的相关性算法,描述了一个文档和查询语句的匹配程度,ES会对每个匹配的查询条件做score,ES5以前用TF-IDF算法,现在用BM25/

    一些基本概念:

    词频(IF):检索词在一片文档中出现的频率。检索词出现的次数/文档总字数。可以把各个词频(除去没有用的词)想加得到一个评分。

    逆文档频率(IDF):log(全部文档数/检索词出现过的文档总数)

    TF-IDF:本质就是将TF加权求和,TF(区块链)IDF(区块链)+TF(的)IDF(的)+TF(应用)*IDF(应用)

    4.1通过Boosting控制相关度

    • 当boost > 1时,打分的相关度相对性提升
    • 当 0 < boost < 1,打分的权重相对性降低
    • 当boost <0,贡献负分
    POST score_test/_search
    {
      "query": {
        "boosting": {
          "positive": {
            "term": {
              "content": "live"
            }
          },
          "negative":{
            "term":{
              "content":"he"
            }
          },
          "negative_boost":0.3
        }
      }
    }
    

    匹配带live的,如果content字段里面包含了he,减分0.3

    5. Query & Filter 多字段查询

    5.1 bool查询

    应用于多个字段,多个条件的符合查询。

    • 一个bool查询是一个或者多个查询的组合。
      • 总共包括4中子句,其中两种会影响算分,两种不影响分数。
    • 多个子句被合并为复合语句的时候,比如bool查询,每个语句的评分都会合并到总评分。
    • 同一个层级的条件具有相同的权重,可以调整嵌套结构控制算分
    字段值 说明
    must 必须匹配,贡献算分
    should 选择性匹配,贡献算分
    must_not filter context查询子句,必须不能匹配,不算评分
    filter filter context 必须匹配,但是不贡献算分。
    • 子查询可以任意顺序出现
    • 可以嵌套多个查询
    • 如果没有must条件,should必须至少满足一条查询

    案例

    GET movies/_search
    {
      "size": 20, 
      "query": {
        "bool": {
          "must": [
            {"term": {
              "title": {
                "value": "bob"
              }
            }}
          ], 
          "filter": [
            {
              "range": {
                "year": {
                  "gte": 1991,
                  "lte": 1994
                }
              }
            }
          ],
          "should": [
            {"term": {
              "id": {
                "value": "3809"
              }
            }},
             {"term": {
              "id": {
                "value": "1994"
              }
            }}
          ],
           "minimum_should_match": 1
        }
      }
    }
    

    标题里面包含bob,发行时间在1991年到1994年,最好id是3809或者1994,should条件最少满足一个。

    嵌套案例,boost会增加。

    GET movies/_search
    {
     "query": {
       "bool": {
         "should": [
           {"bool": {
             "must": [
               {"term": {
                 "title": {
                   "value": "bob",
                   "boost": 1.1
                 }
               }}
             ]
           }}
         ]
       }
     }
    }
    

    5.2 单字符串多字段查询

    案例,查询title或者year出现2012的电影,should换成must表示且。

    GET movies/_search
    {
      "explain": true,
      "query": {
        "bool": {
          "should": [
            {"match": {"title": "2012" }},
            {"match": {"year": "2012"}}
          ]
        }
      }
    }
    

    评分规则:

    • 查询should语句的两个查询
    • 对两个查询的评分求和
    • 乘以匹配语句的总数
    • 除以所有的语句的总数

    基于这个评分规则,可能评分可能不是自己想要的。可以使用Disjunction Max Query,这样就会选择分数最佳的查询的结果的值,返回,不再是相加。

    5.3 Disjunction Max Query

    GET search_test/_search
    {
      "query": {
        "dis_max": {
          "should": [
            {"match": {"title": "php class" }},
            {"match": {"body": "php class"}}
          ],
          "tie_breaker": 0.7
        }
      }
    }
    

    找出最大值,然后把其他的评分乘以0.7,然后想加得到一个新的评分。

    5.3 Mulit Match

    5.3.1 最佳字段(best field)

    当字段之间存在相互竞争,又相互关联。类似title和body,评分来自最匹配的字段。

    案例

    POST movies/_search
    {
      "query": {
        "multi_match": {
          "type": "best_fields", 
          "query": "1993",
          "fields": [
            "title",
            "id"
          ],
          "minimum_should_match": 1
          , "tie_breaker": 0.2
        }
      }
    }
    
    5.3.2 多字段(most field)
    • 在主字段(english analyzer),抽取词干,加入同义词,以匹配更多的项。
    • 相同的文本,加入子字段(standard analyzer),以提供更加精准的匹配。其他字段作为匹配文档提高相关度的信号,匹配的字段越多越好。

    案例

    PUT /titles 
    {
      "mappings": {
        "properties": {
          "title":{
            "type": "text",
            "analyzer": "english",
            "fields": {
              "std":{
                "type":"text",
                "analyzer":"standard"
              }
            }
          }
        }
      }
    }
    

    std字段不会进行分词,是对title的优化
    查询

    GET /titles/_search
    {
      "query": {
        "multi_match": {
          "type": "most_fields", 
          "query": "1",
          "fields": ["title^10","title.std"]
        }
      }
    }
    

    mostfield方式,title设置权重百分10。

    5.3.3 混合字段(cross field)

    对于某些实体,人名、地址。需要在多个字段中确定信息,单个字段只能作为整体的一部分。希望在列出的字段中尽可能找到多的词。

    案例

    POST address/_search
    {
    "query": {
    "multi_match": {
    "query": "poland street w",
    "fields": ["street","city","country","postcode"],
    "type": "cross_fields",
    "operator": "and"
    }
    }
    }

    相对于通过_copyto方式,减少了磁盘空间,同时可以在搜索的时候为单个字段提升权重

    6 search template

    将搜索定义成模板,定义和使用的案例如下

    POST _scripts/tmdb
    {
    "script":{
    "lang":"mustache",
    "source":{
    "_source":["title","overview"],
    "size":20,
    "query":{
    "multi_match":{
    "query":"{{q}}",
    "field":["title","overview"]
    }
    }
    }
    }
    }
    POST tmdb/_search/template
    {
    "id":"tmdb",
    "params": {
    "q":"basketball with"
    }
    }

    7 index alias

    给索引创建一个别名,实现灵停机运维。通过别名,索引的改名和重建程序不用动。

    POST _aliases
    {
      "actions": [
        {
          "add": {
            "index": "movies",
            "alias": "moveis-2019",
            "filter": {
              "range": {
                "year": {
                  "gte": 2012
                }
              }
            }
          }
        }
      ]
    }
    

    相关文章

      网友评论

          本文标题:ES 深入理解搜索

          本文链接:https://www.haomeiwen.com/subject/rvulxhtx.html