美文网首页
(五)高级搜索1

(五)高级搜索1

作者: 木人呆呆 | 来源:发表于2020-08-10 16:16 被阅读0次

    一、基于词项和基于全文的搜索

    1. 基于term的查询
      term 是表达语义的最小单位,搜索和基于统计的语言模型进行自然语言处理都需要处理term
      • 在ES中,Term查询,对输入不做分词,会将输入作为一个整体,在倒排索引中查找准确的词项,并使用相关度算分公式为每个包含包含该词项的文档进行算分
      • 可以通过Constant score将查询转换成一个Filtering,避免算分,并利用缓存,提高性能
    //先存入一些数据
    POST /products/_bulk
    { "index": { "_id": 1 }}
    { "productID" : "XHDK-A-1293-#fJ3","desc":"iPhone" }
    { "index": { "_id": 2 }}
    { "productID" : "KDKE-B-9947-#kL5","desc":"iPad" }
    { "index": { "_id": 3 }}
    { "productID" : "JODL-X-1937-#pV7","desc":"MBP" }
    
    POST /products/_search
    {
      "query": {
        "term": {
          "desc": {
            "value": "iPhone"       
            //"value":"iphone"
          }
        }
      }
    }
    
    //会发现使用“iPhone”检索不出来,只有使用“iphone”才可以检索出来,
    //原因就是“desc”字段存入的时候,做了分词,并且转成了小写,用大写的就检索不出来。
    
    //可以使用这种方式先查看分词后的结果,方便检索不到结果时的问题定位
    GET _analyze
    {
      "analyzer": "standard",
      "text": ["XHDK-A-1293-#fJ3"]
    }
    

    以上这些方法可以针对某个字段做匹配查询,ES默认会给Text类型的字段加上keyword属性,在查询的时候可以采用下面例子给出的这种方式,ES会将包含你要检索词条的所有文档都罗列出来(说白了,就是包含而不相等)。

    但是如果想精确查询某个字段,这里给出一个精确查询的解决方案?(下文会给出解决方案)

    keyword属性

    POST /products/_search
    {
      "query": {
        "term": {
          "productID.keyword": {             //使用keyword属性就可以精确检索
            "value": "XHDK-A-1293-#fJ3"
          }
        }
      }
    }
    

    如果不需要相关性计算,可以使用Constant score将查询转换成filter,从而避免相关性算分机制,还能有效利用缓存功能,能够提升效率

    POST /products/_search
    {
      "query": {
        "constant_score": {         //使用constant_score,转换成filter
          "filter": {
            "term": {
              "productID.keyword":{
                "value":"XHDK-A-1293-#fJ3"
              }
            }
           }
        } 
      }
    }
    
    1. 基于全文的查询
      基于全文本的检索
      • match query
      • match phrase
      • query string query
        查询的时候,会先对输入的查询进行分词,然后每个词项逐个进行底层的查询,最终将结果进行合并,并且为每个文档生成一个算分,输出计算结果。

    展示一个布尔查询的demo

    //插入数据
    POST /products/_bulk
    { "index": { "_id": 1 }}
    { "price" : 10,"avaliable":true,"date":"2018-01-01", "productID" : "XHDK-A-1293-#fJ3" }
    { "index": { "_id": 2 }}
    { "price" : 20,"avaliable":true,"date":"2019-01-01", "productID" : "KDKE-B-9947-#kL5" }
    { "index": { "_id": 3 }}
    { "price" : 30,"avaliable":true, "productID" : "JODL-X-1937-#pV7" }
    { "index": { "_id": 4 }}
    { "price" : 30,"avaliable":false, "productID" : "QQPX-R-3956-#aD8" }
    
    POST products/_search
    {
      "query": {
        "constant_score": {
          "filter": {
            "bool": {
              "must_not":{
                "exists":{
                  "field":"date"
                }
              }
            }
          }
        }
      }
    }
    

    Term查询和全文的查询本质区别在于Term不会做分词,而全文查询会对输入进行分词

    三、相关性算分

    ES 5 之前默认的相关性算分采用TF-IDF,现在采用BM 25

    1. 词频(Term Frequency) 即检索词在一篇文档中的出现的频率
      • 计算方式为:检索词出现的次数/文档的总字数
      • 度量一条查询和结果文档相关性的简单算法:将搜索中每一个词的TF相加,即 TF(term1)+TF(term2)+TF(term3)
      • Stop word,例如“的”这样的词,对贡献相关度几乎没有帮助,就不应该考虑这些词的TF
    2. 逆文档频率(Inverse Document Frequency,IDF),即检索词在所有文档中出现的频率
      简单的计算公式:log(全部文档数/检索词出现过的文档数),TF-IDF的本质是是将TF求和变成加权求和
      举个例子:区块链的应用
    出现的文档数 总文档数 IDF
    区块链 200万 10亿 log(500)=8.96
    10亿 10亿 log(1)=0
    应用 5亿 10亿 log(2)=1

    那么“区块链的应用”的TF-IDF相关性计算公式为:
    TF(区块链)IDF(区块链)+TF(的)IDF(的)+TF(应用)*IDF(应用)

    TF-IDF被公认是信息检索领域最重要的发明,现代的搜索引擎都对TF-IDF进行了细微的优化
    ES 可以对索引,字段分别设置boosting参数

    //存入数据
    PUT testscore/_bulk
    { "index": { "_id": 1 }}
    { "content":"we use Elasticsearch to power the search" }
    { "index": { "_id": 2 }}
    { "content":"we like elasticsearch" }
    { "index": { "_id": 3 }}
    { "content":"The scoring of documents is caculated by the scoring formula" }
    { "index": { "_id": 4 }}
    { "content":"you know, for search" }
    
    //直接查询,会发现"_id"为2的排在前面
    POST /testscore/_search
    {
       "query": {
        "match": {
          "content": "elasticsearch"
        }
      }
    }
    
    //设置boost的值,会对相关性计算的分数产生影响boost>1 增强,0<boost<1 削弱 ,boost<0 会产生负面影响
    
    POST testscore/_search
    {
        "query": {
            "boosting" : {
                "positive" : {
                    "term" : {
                        "content" : "elasticsearch"
                    }
                },
                "negative" : {
                     "term" : {
                         "content" : "like"
                    }
                },
                "negative_boost" : 0.2      
            }
        }
    }
    

    四、Query Context和Filter Context

    在ES中有两种不同的context

    • Query context 相关性算分
    • Filter context 不需要算分,可以利用cache,获得更好的效能提升
      对于多条件组合,可能会组合用到上面两种查询。组合查询中布尔查询又是其中一种常用的查询方式:
    must 必须匹配。贡献算分
    shoud 选择性匹配。贡献算分
    must_not 必须不能匹配。
    filter 必须匹配。不贡献算分
    这里来回答下上文提出的那个不能精确查询的问题

    增加一个count字段进行计数


    在创建文档的时候,增加一个count字段,在查询的时候通过组合查询的方式,可以解决精确查询的问题


    如果标题和描述中都有相同的内容,想要准确检索,也可以采用类似的办法来处理

    //title和content里面都有相同的内容
    DELETE blogs
    POST /blogs/_bulk
    { "index": { "_id": 1 }}
    {"title":"Apple iPad", "content":"Apple iPad,Apple iPad" }
    { "index": { "_id": 2 }}
    {"title":"Apple iPad,Apple iPad", "content":"Apple iPad" }
    
    //采用下面这种检索方式,就可以按照自己的想法,是选择从title还是content 中检索了。
    POST blogs/_search
    {
      "query": {
        "bool": {
          "should": [
            {"match": {
              "title": {
                "query": "apple,ipad",
                "boost": 1.1
              }
            }},
    
            {"match": {
              "content": {
                "query": "apple,ipad",
                "boost":0.5
              }
            }}
          ]
        }
      }
    }
    
    

    相关文章

      网友评论

          本文标题:(五)高级搜索1

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