ES 深入理解搜索

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"http://查不到,"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這些類的查詢實現。

特點:

  • 索引和搜索時都會進行分詞,查詢字符串先傳遞一個合適的分詞器,然后生成可供查詢的列表。
  • 查詢,先對輸入分詞,對每個單詞逐個底層查詢,最終合并結果,并計算分數。

詳細內容見:http://www.lxweimin.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
            }
          }
        }
      }
    }
  ]
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容