elasticsearch 高級搜索示例 es7.0


1 基礎數據

1.1 創建索引

PUT mytest
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "text",
            "analyzer": "standard"
          }
        }
      },
      "tag": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "content": {
        "type": "text",
        "fields": {
          "std": {
            "type": "text",
            "analyzer": "standard"
          },
          "cn": {
            "type": "text",
            "analyzer": "ik_smart"
          }
        }
      },
      "score": {
        "type": "byte"
      },
      "time":{
        "type": "date"
      }
    }
  },
  "settings": {
    "index": {
      "number_of_shards": "1",
      "number_of_replicas": "0"
    }
  }
}

1.2 寫入數據

POST mytest/_doc/001
{
  "title": "好評不錯",
  "tag": "精彩",
  "content": "這里必須有一些內容,來表示這個評論是好評",
  "score": 90,
  "time": 1596441469000
}
POST mytest/_doc/002
{
  "title": "一般評價",
  "tag": "普通",
  "content": "這里可以有一些內容,來表示這個評論是一般的",
  "score": 80,
  "time": 1596355069000
}
POST mytest/_doc/003
{
  "title": "很差的評價",
  "tag": "TCL",
  "content": "這里沒有一些內容,來表示這個評論是OK的",
  "score": 20,
  "time": 1596268669000
}
POST mytest/_doc/004
{
  "title": "超級好評",
  "tag": "精彩",
  "content": "這里必須有一些內容,來表示這個評論是好評好評好評好評好評好評好評好評好評好評好評好評好評",
  "score": 2,
  "time": 1596441469000
}

2 短語匹配

2.1 不指定匹配的 fields 時候, 是否會查找全部字段?

不指定 fields 搜索

POST mytest/_search
{
  "explain": true,
  "query": {
    "match": {
      "content": "好評"
    }
  }
}

搜索結果為 3 條。在 explain 的結果中可以看到, details 評分統計了兩個字段的結果

為了驗證上面結果, 在指定域搜索只能看到一條結果

POST mytest/_search
{
  "query": {
    "match": {
      "content.cn": "好評"
    }
  }
}

2.2 match 和 match_phrase 區別

POST mytest/_search
{
  "explain": false,
  "query": {
    "match": {
      "content.cn":{
        "query": "這里可以有一些內容",
        "analyzer": "ik_smart"
      }
    }
  }
}

"這里可以有一些內容" 通過 ik_smart 分詞器被分成了 [這里 可以 有 一些 內容]
五個詞都放入到 es 中搜索, 所以這里可以搜索出三個結果
可以通過比例限制匹配的結果, 限制到 90% 后, 只能匹配到 1 條結果

POST mytest/_search
{
  "query": {
    "match": {
      "content.cn":{
        "query": "這里可以有一些內容",
        "analyzer": "ik_smart",
        "minimum_should_match": "90%"
      }
    }
  }
}

match_phrase 只能匹配到 1 條結果, 如果把文本換成 "這里可以有內容一些", 就不能匹配到內容了
這時需要使用 slop 完成近似匹配, 允許有順序的差異. 同時, 使用 match 匹配的時候, 詞的順序不影響結果得分

POST mytest/_search
{
  "query": {
    "match_phrase": {
      "content.cn":{
        "query": "這里可以有一些內容",
        "analyzer": "ik_smart",
        "slop": 0
      }
    }
  }
}

2.3 精確搜索的時候, 可以使用默認分詞器, 以達到精確的目的

在搜索中輸入 "以有一些內容" 不完整的內容, 也可以搜索到精確的結果
修改為 match 可以

POST mytest/_search
{
  "query": {
    "match_phrase": {
      "content.std":{
        "query": "以有一些內容",
        "analyzer": "standard"
      }
    }
  }
}

3 自定義打分

3.1 打分公式

score(q,d) = queryNorm(q)            //歸一化因子
             ·coord(q,d)             //協調因子
             ·∑( tf(t in d)          //詞頻
                ·idf(t)²             //逆向文檔頻率
                ·t.getBoost()        //權重
                ·norm(t,d)           //字段長度歸一值
              )(t in q)

queryNorm 查詢歸化因子: 會被應用到每個文檔, 不能被更改, 總而言之, 可以被忽略
coord 協調因子: 可以為那些查詢詞包含度高的文檔提供獎勵, 文檔里出現的查詢詞越多, 它越有機會成為好的匹配結果
協調因子將評分與文檔里匹配詞的數量相乘,然后除以查詢里所有詞的數量,如果使用協調因子,評分會變成:
文檔里有 fox → 評分: 1.5 * 1 / 3 = 0.5
文檔里有 quick fox → 評分: 3.0 * 2 / 3 = 2.0
文檔里有 quick brown fox → 評分: 4.5 * 3 / 3 = 4.5
協調因子能使包含所有三個詞的文檔比只包含兩個詞的文檔評分要高出很多

3.2 提升查詢權重

POST mytest/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": {"query": "好評", "boost": 10}
          }
        },
        {"match": {"content": "有一些內容"}
        }
      ]
    }
  }
}

3.3 結合 function_score 查詢 與 field_value_factor 查詢可以實現按照文檔的字段來影響文檔評分

POST mytest/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {"query": "好評","fields": ["title", "content"]}
      },
      "functions": [
        {"field_value_factor": {"field": "score"}}
      ]
    }
  }
}

new_score = old_score * number_of_votes
這樣會導致 votes 為 0 的文檔評分為 0,而且 votes 值過大會掩蓋掉全文評分

3.4 一般會使用 modifier 參數來平滑 votes 的值

POST mytest/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {"query": "好評","fields": ["title", "content"]}
      },
      "functions": [
        {"field_value_factor": {"field": "score", "modifier": "log1p"}}
      ]
    }
  }
}

應用值為 log1p 的 modifier 后的評分計算公式:
new_score = old_score * log(1 + number_of_votes)

modifier 的可以為: none ,log ,log1p ,log2p ,ln ,ln1p ,ln2p ,square ,sqrt ,reciprocal

3.5 factor 可以通過將 votes 字段與 factor 的積來調節受歡迎程度效果的高低

"functions": [
        {"field_value_factor": {"field": "score", "modifier": "ln1p", "factor": 10}}
      ]

添加了 factor 會使公式變成這樣:
new_score = old_score * log(1 + factor * number_of_votes)

3.6 通過參數 boost_mode 來控制函數與查詢評分 _score 合並后的結果,參數接受的值

multiply: 評分 _score 與函數值的積(默認)
sum: 評分 _score 與函數值的和
min: 評分 _score 與函數值間的較小值
max: 評分 _score 與函數值間的較大值
replace: 函數值替代評分 _score

"functions":[],
"boost_mode": "sum"

之前請求的公式現在變成下面這樣:
new_score = old_score + log(1 + 0.1 * number_of_votes)

3.7 可以使用 max_boost 參數限制一個函數的最大效果

"boost_mode": "sum"
"max_boost": 1.5

無論 field_value_factor 函數的結果如何,最終結果都不會大於 1.5 。
注意 max_boost 只對函數的結果進行限制,不會對最終評分 _score 產生直接影響。

3.8 評分模式 score_mode

每個函數返回一個結果,所以需要一種將多個結果縮減到單個值的方式,然后才能將其與原始評分 _score 合並。
評分模式 score_mode 參數正好扮演這樣的角色, 它接受以下值:

multiply : 函數結果求積(默認)。
sum : 函數結果求和。
avg : 函數結果的平均值。
max : 函數結果的最大值。
min : 函數結果的最小值。
first : 使用首個函數(可以有過濾器,也可能沒有)的結果作為最終結果
在本例中,我們將每個過濾器匹配結果的權重 weight 求和,並將其作為最終評分結果,所以會使用 sum 評分模式。
不與任何過濾器匹配的文檔會保有其原始評分, _score 值的為 1 。

3.9 衰減函數

這需要使用 function_score 查詢提供的一組 衰減函數(decay functions)
linear 線性函數
exp 指數函數
gauss 高斯函數

所有三個函數都接受如下參數:
origin:中心點 或字段可能的最佳值,落在原點 origin 上的文檔評分 _score 為滿分 1.0 。
scale:衰減率,即一個文檔從原點 origin 下落時,評分 _score 改變的速度。(例如,每 £10 歐元或每 100 米)。
decay:從原點 origin 衰減到 scale 所得的評分 _score ,默認值為 0.5 。
offset:以原點 origin 為中心點,為其設置一個非零的偏移量 offset 覆蓋一個范圍,而不只是單個原點。在范圍 -offset <= origin <= +offset 內的所有評分 _score 都是 1.0

      "functions": [
        {
          "exp": {
            "time": {
              "origin": "1596530751000",
              "scale": "10d",
              "offset": "5d",
              "decay": 0.5
            }
          }
        }
      ]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM