<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          干貨 | Elasticsearch 向量搜索的工程化實戰(zhàn)

          共 9919字,需瀏覽 20分鐘

           ·

          2021-12-24 20:01

          1、背景

          作為一家搜索引擎公司,我們會很倚賴 ES 幫忙處理包括文章召回,數(shù)據(jù)源劃分,實體、標簽管理等任務,而且都收到了不錯的結果。

          最近我們需要對行業(yè)知識庫進行建模,其中可能會涉及到實體匹配、模糊搜索、向量搜索等多種召回和算分方式,最終我們選擇了通過 ES 7.X (最終選擇 7.10)里的新功能,Dense vector 幫忙一起完成這部分的需求。

          2、技術選型

          2.1 解決方案需求

          1. 支持向量搜索
          2. 支持多維度篩選、過濾
          3. 吞吐速率
          4. 學習、使用成本
          5. 運維成本

          2.2 使用場景設計

          1. 離線數(shù)據(jù)準備
            1. 在離線數(shù)據(jù)構建完成后,存入該引擎
            2. 引擎對數(shù)據(jù)中各字段進行索引
          2. 在線數(shù)據(jù)召回
            1. 根據(jù) query 理解結果構建的 query 語句進行數(shù)據(jù)召回
            2. 對結果進行一定的篩選
            3. 對結果進行一定的打分排序

          2.3 數(shù)據(jù)結構設計

          在確定了數(shù)據(jù)的使用場景我們確定了數(shù)據(jù)結構中,大致會包含以下一些字段

          1. 唯一 id:用以做知識的去重和快速獲取
          2. 實體、屬性、取值:用來描述知識的具體內(nèi)容
          3. 置信度:用來描述知識的可信度
          4. 分類 flag:知識主要分類及推薦 category 等
          5. 向量表示:作為知識相似性、相關性召回、打分的依據(jù)
          6. ref 信息:用來回溯解析/獲取該知識的源信息
          7. 其他屬性:包括生效、刪除、修改時間等支持性的通用屬性

          2.4 解決方案對比

          為了能支持上述的使用需求,我們對比了包括 ES、Faiss 等多種解決方案。其中,FaissSPTAG 只是核心算法庫,需要進行二次開發(fā)包裝成服務;Milvus1.x 版本中只能存儲 id向量,不能完整的滿足我們的使用需求;基于集群穩(wěn)定性和可維護性等考慮,相對于后置插件的部署,我們更傾向于使用 ES 的原生功能,所以選擇 ES 的原生向量搜索功能作為我們的最終選擇。

          對比參考:

          種類實現(xiàn)語言客戶端支持多條件召回學習成本引入成本運維成本分布式性能社區(qū)備注
          ElasticsearchJavaJava/Pythonyesyes活躍原生功能
          FaissPythonPythonnono一般需要二次開發(fā)
          MilvusPython + GoLangPython/Java/GoLangnono一般1.x 功能不全
          OpenDistro Elasticsearch KNNJava + C++Java/Pythonyesyes一般內(nèi)置插件
          SPTAGC++Python + C#nono一般需要二次開發(fā)

          3、數(shù)據(jù)流轉(zhuǎn)流程

          3.1 離線數(shù)據(jù)處理部分

          1. 從多數(shù)據(jù)源采集數(shù)據(jù)
          2. 數(shù)據(jù)清洗及預處理
          3. 通過算法引擎提取知識
          4. 通過算法引擎將知識轉(zhuǎn)換為向量
          5. 將知識的基礎信息連同向量數(shù)據(jù)存入 ES

          3.2 在線數(shù)據(jù)召回部分

          1. 從前端獲取搜索條件
          2. 通過 query 理解模塊進行檢索條件解析
          3. ES 中進行搜索
          4. 對結果進行分數(shù)調(diào)整
          5. 返回前端

          4、ES 向量搜索的使用示例

          4.1 索引設計

          Settings

          {
          "settings": {
          "number_of_shards": 3,
          "number_of_replicas": 2,
          "index": {
          "routing": {
          "allocation": {
          "require": {
          "node_group": "hot" // 1)
          }
          }
          },
          "store": {
          "preload": [ // 2)
          "knowledge",
          "category",
          "available",
          "confidence",
          "del",
          "kid"
          ]
          },
          "search": {
          "slowlog": {
          "threshold": {
          "query": {
          "warn": "1s" // 3)
          },
          "fetch": {
          "warn": "1s" // 3)
          }
          }
          }
          },
          "translog": {
          "flush_threshold_size": "512mb", // 4)
          "sync_interval": "5m", // 4)
          "durability": "async" // 4)
          },
          "sort": {
          "field": [ // 5)
          "kid",
          "confidence"
          ],
          "order": [ // 5)
          "asc",
          "desc"
          ]
          }
          }
          }
          }
          • 說明:
          1. 由于向量數(shù)據(jù)較大,所以傾向于將整個索引都放置在硬件性能更好的節(jié)點
          2. 為了支持高性能過濾,將常用的字段預先加載在內(nèi)存中
          3. 對慢查詢開啟日志方便后續(xù)性能問題的調(diào)查
          4. 知識庫的重建是離線的,會在更新時進行大量寫入,所以對 translog 的提交間隔拉長,加快寫入速度
          5. 在實際使用中kid是自增id,同時可能會對知識的置信度做排序等,所以會使用 sort field 存儲這兩個字段

          Mapping

          {
          "mappings": {
          "properties": {
          "kid": {
          "type": "keyword"
          },
          "knowledge": {
          "type": "keyword"
          },
          "knowledge_phrase": { // 1)
          "type": "text",
          "analyzer": "faraday"
          },
          "attribue": { // 1)
          "type": "keyword",
          "fields": {
          "phrase": {
          "type": "text",
          "analyzer": "faraday"
          }
          }
          },
          "value": { // 1)
          "type": "keyword",
          "fields": {
          "phrase": {
          "type": "text",
          "analyzer": "faraday"
          }
          }
          },
          "confidence": { // 2)
          "type": "double"
          },
          "category": {
          "type": "keyword"
          },
          "vector": { // 3)
          "type": "dense_vector",
          "dims": 512
          },
          "ref": {
          "type": "text",
          "index": false
          },
          "available": {
          "type": "keyword"
          },
          "del": {
          "type": "keyword"
          },
          "create_timestamp": {
          "type": "date",
          "format": [
          "strict_date_hour_minute_second",
          "yyyy-MM-dd HH:mm:ss"
          ]
          },
          "update_timestamp": {
          "type": "date",
          "format": [
          "strict_date_hour_minute_second",
          "yyyy-MM-dd HH:mm:ss"
          ]
          }
          }
          }
          }
          • 說明:
          1. 除了對知識條目的完整搜索之外,還會需要進行模糊檢索,我們使用了自研的 farady 分詞器對知識條目的各部分進行了分詞處理
          2. 知識庫中的知識條目會有一部分進行專家/人工審核和維護,所以會對不同的條目設置不同的置信度
          3. 數(shù)據(jù)預處理之后會轉(zhuǎn)成 512 位的向量存在這個字段中

          4.2 數(shù)據(jù)流轉(zhuǎn)

          • 離線部分:
          1. 數(shù)據(jù)采集及清洗
          2. 通過 模型A 從文章中找到知識條目
          3. 通過 模型B 將知識條目轉(zhuǎn)化成向量
            1. 此處 模型A 模型B 為自研模型,運用了包括知識密度計算等算法以及 bert tersonflow 等框架
          4. 將原文、知識條目等核心內(nèi)容插入數(shù)據(jù)庫
          5. 將核心知識內(nèi)容、向量等組裝成檢索單元插入 ES
          6. 專家團隊會針對數(shù)據(jù)庫中的知識條目進行審核、修改和迭代
          7. 算法團隊會根據(jù)知識條目的更新以及其他的標注對數(shù)據(jù)鏈路中的模型進行迭代,對在線知識庫進行更新
          • 在線部分:
          1. 前端收到請求之后調(diào)用 query 理解 組件進行分析
          2. 剔除無效內(nèi)容之后,找出 query 里的分類信息等意圖之后,構建用來召回的向量和相關的篩選條件
          3. 通過組合出來的 ESquery 條件對知識庫進行篩選,并配合置信度等對結果進行調(diào)整
          4. 對召回結果進行不同策略的分數(shù)調(diào)整和排序,最后輸出給前端

          4.3 示例 query

          POST knowledge_current_reader/_search
          {
          "query": {
          "script_score": {
          "query": {
          "bool": {
          "filter": [
          {
          "term": {
          "del": 0
          }
          },
          {
          "term": {
          "available": 1
          }
          }
          ],
          "must": {
          "bool": {
          "should": [
          {
          "term": {
          "category": "type_1",
          "boost": 10
          }
          },
          {
          "term": {
          "category": "type_2",
          "boost": 5
          }
          }
          ]
          }
          },
          "should": [
          {
          "match_phrase": {
          "knowledge_phrase": {
          "query": "some_query",
          "boost": 10
          }
          }
          },
          {
          "match": {
          "attribute": {
          "query": "some_query",
          "boost": 5
          }
          }
          },
          {
          "match": {
          "value": {
          "query": "some_query",
          "boost": 5
          }
          }
          },
          {
          "term": {
          "knowledge": {
          "value": "some_query",
          "boost": 30
          }
          }
          },
          {
          "term": {
          "attribute": {
          "value": "some_query",
          "boost": 15
          }
          }
          },
          {
          "term": {
          "value": {
          "value": "some_query",
          "boost": 10
          }
          }
          }
          ]
          }
          },
          "script": {
          "source": "cosineSimilarity(params.query_vector, 'vector') + sigmoid(1, Math.E, _score) + (1 / Math.log(doc['confidence'].value))",
          "params": {
          "query_vector": [ ... ]
          }
          }
          }
          }
          }
          • 說明:
          1. 上述 query 的條件、參數(shù)僅做示意,屬于實際線上使用的脫敏、簡化版
          2. 計算公式為迭代中某一版,后續(xù)調(diào)整和升級并未體現(xiàn)
          3. 邊界條件及空值在輔助服務和 pipeline 中進行處理,簡化了其中邊界條件處理和判斷部分邏輯

          5、遇到的問題

          5.1 響應時間長

          由于需要進行向量計算,ES 需要耗費大量時間、資源做距離計算,為此我們進行了以下一些優(yōu)化:

          1. 特征值截取小數(shù)位數(shù):
            1. 為了保證特征的表征,我們并沒有調(diào)整由 bert 框架輸出的向量位數(shù)
            2. 在權衡了存取效率、數(shù)據(jù)精度和計算速度之后,我們將每一個 label 的精度由16位截取為5位小數(shù)
            3. 這樣雖然損失了部分精度(約 X%),但是大大降低了存取和計算時間(約 Y%
          2. 在進行 query 之前預先對意圖、可能分類進行分析
            1. 為了減少納入計算排序的數(shù)據(jù),我們會在 query 組裝之前對原始 query 內(nèi)容進行分析
            2. 配合用戶行為埋點和專家的先驗知識,將知識進行大致分類,并對 query 和分類進行不同權重的匹配
            3. 這樣雖然降低了召回率(約 X%),但增加了準確性(約 Y%),同時也提高了部分計算效率(約 Z%
          3. 精簡計算公式
            1. 將一部分分數(shù)計算的邏輯外置,盡可能精簡 ES 需要處理的運算邏輯
            2. 在召回之后增加多種打分策略,通過配置進行應用、權重調(diào)整等操作
            3. 這樣降低了 ES 的響應時間(約 X%),同時通過外置的打分公式調(diào)整,間接的提高了準確性(約 Y%

          5.2 知識質(zhì)量參差不齊

          由于知識條目是通過算法進行抽取的,而且知識還會存在一定的時效性,可能造成知識的不準確等問題,為此我們進行了以下一些優(yōu)化:

          1. 持續(xù)的算法迭代:
            1. 根據(jù)用戶埋點信息和標注信息對模型進行持續(xù)迭代
            2. 選取更加優(yōu)質(zhì)的知識抽取結果對線上數(shù)據(jù)進行全量/增量更新
            3. 經(jīng)過 X 批次的迭代,將知識的正確性從 Y% 提高到了 Z%
          2. 對模型輸出的知識進行后置處理
            1. 將僅存在部分助詞(如)差異的知識條目進行過濾、合并
            2. 給部分熱門的知識條目設置過期時間,并通過部分人工審核的方式干預知識條目的生產(chǎn)
            3. 維護專家知識庫的方式對可信知識進行標記及提權
            4. 維護了 X 類目的 Y 條專家知識,同時經(jīng)過人工干預了大概 Z% 的知識條目,將知識的正確性從 W% 提高到了 K%

          結論與展望

          本文依托我們公司的使用場景,對圍繞 ES 向量字段(Dense vector)構建的一個系統(tǒng)進行了大致描述,同時對一些常見問題及解決方案進行了闡述。

          目前該方案支持了我們對于知識庫的相關搜索功能,相較于之前的純基于實體識別和 ngram 匹配的方案整體準確率和召回率都有將近兩位數(shù)百分比的提升。

          未來我們會對整個系統(tǒng)的響應速度、穩(wěn)定性進行提升,并對知識庫的構建效率以及知識的準確性持續(xù)進行迭代。

          作者介紹

          死敵wen,Elastic 認證工程師,搜索架構師,10年+工作經(jīng)驗,畢業(yè)于復旦大學。

          博客:https://blog.csdn.net/weixin_40601534

          Github:https://github.com/godlockin

          說明

          上個月,死磕 Elasticsearch 知識星球搞了:“群智涌現(xiàn)”杯輸出倒逼輸入——Elastic干貨輸出活動。

          后續(xù)會不定期逐步推出系列文章,目的:以文會友,“輸出倒逼輸入”。

          推薦

          1、重磅 | 死磕 Elasticsearch 方法論認知清單(2021年國慶更新版)
          2Elasticsearch 7.X 進階實戰(zhàn)私訓課(口碑不錯)

          短時間快習得多干貨!

          已帶領77位球友通過 Elastic 官方認證!


          比同事搶先一步學習進階干貨
          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一插菊花综合网 | 91成人视频 亚洲一区二区 | 三级精品| 午夜视频网址 | 最近中文字幕中文翻译歌词 |