首頁 > 後端開發 > Golang > 主體

用 Go 建立高效能全文搜尋引擎

Linda Hamilton
發布: 2024-11-02 09:44:31
原創
916 人瀏覽過

1. 簡介

當今世界,大量資訊不斷產生,有效存取相關資料至關重要。全文搜尋引擎透過索引文字內容實現快速資料檢索,構成從搜尋引擎到資料分析工具等應用程式的支柱。鑑於涉及海量資料集,搜尋引擎需要採用複雜的方法來索引和查詢以獲得最佳效能。

本部落格將引導您使用 Go 建立全文搜尋引擎,重點關注資料流、多執行緒和高效索引結構等進階概念。您將了解如何以節省記憶體的方式處理和搜尋大型資料集(特別是維基百科摘要)。透過遵循本指南,您將深入了解如何利用 Go 的並發模型及其對高效能應用程式的適用性。


2. 技術堆疊

該專案的技術堆疊包括 Go 作為主要程式語言,因其簡單的語法、強大的標準庫和本機並發支援而被選中。以下是基本工具和函式庫的詳細資訊:

  • 程式語言:Go(Golang)

    • Go 為並發應用程式提供了一個高效的環境,並提供了在不犧牲效能的情況下管理多個任務的工具。
  • 圖書館

    • Gzip 和 XML 解析:這些對於處理維基百科的壓縮 XML 資料至關重要。標準的encoding/xml和compress/gzip函式庫允許直接解析和解壓縮,非常適合Go的生態系。
    • Sync 套件:這個核心 Go 套件用於管理並發進程,其結構包括用於協調 goroutine 的sync.WaitGroup 和用於處理資料存取的sync.Mutex。
    • kljensen/snowball:這個函式庫提供詞幹,透過將單字減少為其基本形式來實現更好的搜尋最佳化。
  • 資料來源

    • 專案利用維基百科摘要,這是一個包含維基百科文章摘要的壓縮 XML 檔案。該資料集多樣化且足夠大,足以作為搜尋引擎功能的實際測試。在此下載

3. 理念的根源

問題陳述

隨著資料量不斷增長,有效檢索有意義的資訊是一項重大挑戰。搜尋引擎需要快速管理和存取大量文字資料集,這個問題導致了倒排索引、標記化和資料規範化等創新。

靈感與研究

Elasticsearch 等流行工具展示了基於強大索引和檢索技術構建的全文搜尋引擎的強大功能。受到這些行業標準引擎的啟發,該項目尋求在 Go 中實現類似的解決方案。 Go 的簡單性、效能和並發特性使其非常適合這項任務,提供了探索主要搜尋引擎使用的概念並將其定制為自訂實現的能力。

目標用戶

這個專案是為那些有興趣了解搜尋引擎如何運作的人,以及渴望探索 Go 並發模型的開發人員和愛好者而設計的。透過提供實務經驗,這是一個了解 Go 如何處理即時索引和搜尋等密集任務的機會,特別是對於對後端和全端開發感興趣的人。


4. 建立這個專案的原因

實踐學習

該專案提供了一種實用的方法來掌握 Go 中的串流處理和多線程,以及深入研究全文搜尋引擎的工作原理。它允許對索引、標記化和文件處理進行實驗,從而提供對搜尋引擎內部結構的全面了解。

Go 的效率

透過使用Go,你會發現它的高並發效率。 Go 非常適合建立需要並行運行多個任務的應用程序,使其成為該專案以效能為中心的目標的理想語言。

提升圍棋技能

該專案建立了 Go 的高級技能,Go 是一種廣泛用於雲端原生和可擴展應用程式的語言。它提供了實現多線程和並發解決方案的機會,同時強調了 Go 在高需求應用程式中管理記憶體和效能的獨特方法。


5. 工作流程與關鍵概念

工作流程概述

引擎遵循涉及多個階段的結構化工作流程:

  1. 文檔載入:以串流方式從 XML 文件載入和解壓縮文檔,以最大限度地減少記憶體使用。
  2. 標記化和文字處理:每個文件都被標記化,透過轉換為小寫、刪除停用詞和應用詞幹來規範文字。
  3. 索引建構:處理後的令牌儲存在倒排索引中,將每個令牌對應到包含它的文件ID。
  4. 保存/加載索引:可以保存最終索引並從磁碟加載,為將來的會話保留索引工作並加快搜尋引擎的初始化。

Building a High-Performance Full-Text Search Engine in Go

資料流和處理

串流處理允許一次處理一個文檔,而無需將整個資料集載入到記憶體中。 LoadDocuments 函數即時處瞭解壓縮和解析,將每個文件送入通道。此設定可確保系統透過順序處理資料來處理大型資料集,從而減少記憶體壓力。

文檔處理中的並發

文件處理是並發的,多個 goroutine 負責解析、分析和索引文件。這種並發性顯著加速了索引過程並允許即時搜尋更新。


6. 串流與多執行緒簡介

Go 中的串流

定義和目的

串流是一種技術,資料在可用時以區塊的形式處理,而不是一次載入全部資料。這對於大型資料集特別有用,由於記憶體限制,載入整個資料集是不切實際的。

大型資料集的好處

串流處理在任何給定時間僅處理一小部分數據,有助於有效管理內存,這對於該搜尋引擎來說是理想的選擇。系統不需要一次載入所有維基百科摘要;相反,它以穩定的流程單獨處理每個文件。

實施例

LoadDocuments 函數以串流方式載入和解壓縮文檔,使用 Go 的encoding/xml 和 compress/gzip 函式庫來解析每個文檔並將其傳送到處理通道。

Go 中的多線程

定義和核心概念

多執行緒允許同時執行程式碼段,透過同時執行多個操作來提高應用程式效能。 Go 的原生並發模型,具有 goroutine 和通道,提供了實現多執行緒的簡單方法。

Go 中的並發

Go 中的並發是透過 goroutine 實現的,goroutines 是允許多個函數同時運行的輕量級線程。 Channels 實現了 goroutine 之間的通信,確保資料可以安全地傳遞,而不需要複雜的同步。

這裡是如何使用的

在這個搜尋引擎中,多個 goroutine 同時處理文件處理和索引。例如,AddStreamed 函數會從文件通道中讀取資料並同時為每個文件建立索引,從而可以在大型資料集上更快建立索引。

挑戰與最佳化

管理多個執行緒可能會導致競爭條件等問題,即多個執行緒同時存取共享資源。 Go 的同步套件以及 Mutex 和 WaitGroup 透過同步資料存取並確保任務在繼續下一步之前完成來幫助避免這些問題。


全文搜尋引擎的功能和特點

這個全文搜尋引擎利用 Go 的並發能力來建立高效能的索引和搜尋機制。透過使用資料流和多線程,應用程式可以有效地處理大型資料集(例如維基百科摘要),而不會造成記憶體過載。本節介紹程式碼中使用的主要功能、特性和關鍵方法。


1. 搜尋引擎的核心功能

  • 高效率索引:使用倒排索引可以快速擷取與查詢字相符的文件。
  • 並發處理:多執行緒文件索引和搜尋操作,實現快速、非阻塞操作。
  • 帶有元資料的文件儲存:將元資料(例如標題和 URL)與索引內容一起存儲,從而允許檢索完整的文件詳細資訊。
  • 索引的持久性:索引可以儲存到磁碟或從磁碟加載,允許跨會話重複使用搜尋索引。
  • 資料過濾和標準化:包括停用詞刪除、大小寫標準化和詞幹標準化搜尋標記。

2. 關鍵組件和功能

一個。文件載入和串流媒體

LoadDocuments 函數處理從壓縮 XML 文件載入文檔,將其解壓縮並解析為流。這種方法記憶體效率高,對於大型資料集特別有用。

程式碼片段:載入文檔

// LoadDocuments loads documents from a gzip-compressed XML file and sends them through a channel.
func LoadDocuments(path string, docChan chan<- Document) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close()

    gz, err := gzip.NewReader(f)
    if err != nil {
        return err
    }
    defer gz.Close()

    dec := xml.NewDecoder(gz)
    dump := struct {
        Documents []Document `xml:"doc"`
    }{}

    if err := dec.Decode(&dump); err != nil {
        return err
    }

    for i, doc := range dump.Documents {
        doc.ID = i
        docChan <- doc
    }
    return nil
}
登入後複製
登入後複製
登入後複製

這裡:

  • XML 檔案是動態解壓縮和解析的,這表示整個檔案不會立即載入。
  • 然後將文件傳輸到通道 docChan,以便在載入後立即對其進行處理,非常適合併發索引。

b.標記化和文本分析

tokenizer.go 檔案包含透過標記化、大小寫標準化、停用詞刪除和詞幹擷取來規範化和標準化文字的函數。

程式碼片段:分析

// LoadDocuments loads documents from a gzip-compressed XML file and sends them through a channel.
func LoadDocuments(path string, docChan chan<- Document) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close()

    gz, err := gzip.NewReader(f)
    if err != nil {
        return err
    }
    defer gz.Close()

    dec := xml.NewDecoder(gz)
    dump := struct {
        Documents []Document `xml:"doc"`
    }{}

    if err := dec.Decode(&dump); err != nil {
        return err
    }

    for i, doc := range dump.Documents {
        doc.ID = i
        docChan <- doc
    }
    return nil
}
登入後複製
登入後複製
登入後複製

此功能:

  • 文字標記為單字或標記。
  • 標記轉換為小寫以確保不區分大小寫。
  • 刪除停用詞,減少索引中不必要的資料。
  • 將標記詞幹到其根形式,確保搜尋一致性(例如,「running」變為「run」)。

c.建構與管理倒排索引

Index 結構是核心資料結構,保存倒排索引和文件儲存。倒排索引是一個映射,其中每個標記(單字)映射到包含該單字的文檔 ID 列表,從而實現高效搜尋。

程式碼片段:將文件新增至索引

// analyze analyzes the text and returns a slice of tokens.
func analyze(text string) []string {
    tokens := tokenize(text)
    tokens = lowercaseFilter(tokens)
    tokens = stopwordFilter(tokens)
    tokens = stemmerFilter(tokens)
    return tokens
}
登入後複製

AddDocument 函數:

  • 鎖定索引以防止並發寫入期間出現競爭情況。
  • 將文件依ID儲存於docStore中,實現依ID全文檢索。
  • 透過處理文件中的每個標記並將其 ID 新增至標記清單中來建立倒排索引,確保快速尋找。

儲存和檢索索引

為了允許索引的持久使用,index.go中的Save和Load方法使用Go的encoding/gob套件進行序列化和反序列化。

// AddDocument adds a single document to the index.
func (idx *Index) AddDocument(doc Document) {
    idx.mu.Lock()
    defer idx.mu.Unlock()

    idx.docStore[doc.ID] = doc
    for _, token := range analyze(doc.Text) {
        ids := idx.index[token]
        if ids != nil && ids[len(ids)-1] == doc.ID {
            continue
        }
        idx.index[token] = append(ids, doc.ID)
    }
}
登入後複製

d.使用串流並發文件索引

使用AddStreamed方法,來自docChan的文檔被同時索引。多個 goroutine 處理文件新增流程,顯著加快大型資料集的索引速度。

程式碼片段:AddStreamed

// Save serializes both the index and docStore to a file.
func (idx *Index) Save(filePath string) error {
    idx.mu.RLock()
    defer idx.mu.RUnlock()

    file, err := os.Create(filePath)
    if err != nil {
        return err
    }
    defer file.Close()

    encoder := gob.NewEncoder(file)
    if err := encoder.Encode(idx.index); err != nil {
        return err
    }
    if err := encoder.Encode(idx.docStore); err != nil {
        return err
    }

    return nil
}
登入後複製

這個方法:

  • 啟動多個 goroutine 並行處理文件。
  • 使用 WaitGroup 等待所有 goroutine 完成,確保在繼續之前處理所有文件。

e.搜尋文件

index.go 中的搜尋功能可以透過尋找包含所有查詢標記的文件來有效地檢索與搜尋查詢相符的文件 ID。

程式碼片段:搜尋

// AddStreamed adds documents from a channel to the index concurrently.
func (idx *Index) AddStreamed(docChan <-chan Document) {
    var wg sync.WaitGroup
    numWorkers := 4 // Number of concurrent workers

    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for doc := range docChan {
                idx.AddDocument(doc)
            }
        }()
    }
    wg.Wait()
}
登入後複製

搜尋功能:

  • 將查詢文字分析為標記,然後檢查每個標記是否存在於索引中。
  • 尋找每個標記的 ID 的交集,僅傳回包含查詢中所有術語的文件。

顯示搜尋結果

PrintResultsTable 方法格式化並顯示符合的文件 ID 以及標題和文字片段,以提高可讀性。

// LoadDocuments loads documents from a gzip-compressed XML file and sends them through a channel.
func LoadDocuments(path string, docChan chan<- Document) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close()

    gz, err := gzip.NewReader(f)
    if err != nil {
        return err
    }
    defer gz.Close()

    dec := xml.NewDecoder(gz)
    dump := struct {
        Documents []Document `xml:"doc"`
    }{}

    if err := dec.Decode(&dump); err != nil {
        return err
    }

    for i, doc := range dump.Documents {
        doc.ID = i
        docChan <- doc
    }
    return nil
}
登入後複製
登入後複製
登入後複製

此表格檢視有助於快速驗證結果並提高可讀性,因為它包含每個符合文件的文字片段。


7. 未來範圍

這個全文搜尋引擎是建立綜合搜尋系統的堅實基礎,但有一些增強功能可以使其更加強大和功能豐富:

1. 分散式處理

  • 目標:透過在多台機器上分配工作負載來擴展搜尋引擎以處理更大的資料量。
  • 實作:透過跨伺服器分散文件索引和查詢,搜尋引擎可以處理更多查詢和更大的資料集。 gRPC 或 HTTP/2 等技術可以促進分散式節點之間的高效通訊。

2. 進階查詢支援

  • 目標:允許使用者使用運算符(例如 AND、OR、NOT)和鄰近查詢執行更複雜的搜尋。
  • 實作:擴展索引演算法以支援複雜查詢,例如精確短語和通配符搜索,增強搜尋靈活性。

3. 即時索引更新

  • 目標:使引擎能夠在新增文件時動態更新索引。
  • 實作:即時索引功能將允許新增文件而無需完全重新索引,使其成為處理頻繁更新內容的應用程式的理想選擇。

4. 機器學習整合排名

  • 目標:透過結合機器學習模型根據使用者行為和相關性對文件進行排名來提高結果相關性。
  • 實現:透過分析過去的搜尋資料和使用者偏好,引擎可以優先考慮更相關的文檔,使搜尋結果更加準確和個人化。

5. 改進的自然語言處理(NLP)

  • 目標:使用 NLP 改進分詞、詞幹和同義詞支持,使引擎能夠更直觀地處理用戶查詢。
  • 實作:利用 NLP 技術將透過考慮同義詞、複數和上下文來增強查詢匹配,從而提高引擎解釋使用者意圖的能力。

8. 結果截圖

Building a High-Performance Full-Text Search Engine in Go


9. 結論

使用 Go 建立全文搜尋引擎是一個實用項目,用於理解並發、多執行緒和資料流等複雜的程式設計概念。該專案展示了 Go 在保持高效能的同時高效處理大型資料集的能力。透過專注於高效索引和多線程處理,該搜尋引擎實現了令人印象深刻的速度和記憶體效率。

透過這個過程,我們探索了搜尋引擎的關鍵元件——串流、標記化、反向索引和多執行緒——並了解了這些元素如何組合在一起以創建響應式且資源敏感的搜索解決方案。透過分散式處理和 NLP 整合等潛在增強功能,此搜尋引擎可以進一步發展,提供更強大的功能。

這裡獲得的經驗不僅展示了 Go 的效能,而且還為建立可滿足資料密集型環境需求的可擴展的實際應用程式奠定了基礎。

以上是用 Go 建立高效能全文搜尋引擎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!