當前位置: 妍妍網 > 碼農

一個 Python 的輕量級搜尋工具 -- Whose

2024-03-17碼農

來源丨網路

本文將簡單介紹 Python 中的一個輕量級搜尋工具 Whoosh,並給出相應的使用範例程式碼。

# Whoosh 簡介

Whoosh 由 Matt Chaput 建立,它一開始是一個為 Houdini 3D 動畫軟體包的線上文件提供簡單、快速的搜尋服務工具,之後便慢慢成為一個成熟的搜尋解決工具並已開源。

Whoosh 純由 Python 編寫而成,是一個靈活的,方便的,輕量級的搜尋引擎工具,現在同時支持 Python2、3,其優點如下:

  • Whoosh 純由 Python 編寫而成,但很快,只需要 Python 環境即可,不需要編譯器;

  • 預設使用 Okapi BM25F 排序演算法,也支持其他排序演算法;

  • 相比於其他搜尋引擎,Whoosh 會建立更小的 index 檔;

  • Whoosh 中的 index 檔編碼必須是 unicode;

  • Whoosh 可以儲存任意的 Python 物件。

  • Whoosh 的官方介紹網站為:https://whoosh.readthedocs.io/en/latest/intro.html 。相比於 ElasticSearch 或者 Solr 等成熟的搜尋引擎工具,Whoosh 顯得更輕便,操作更簡單,可以考慮在小型的搜尋計畫中使用。

    # Index & query

    對於熟悉 ES 的人來說,搜尋的兩個重要的方面為 mapping 和 query,也就是索引的構建以及查詢,背後是復雜的索引儲存、query 解析以及排序演算法等。如果你有 ES 方面的經驗,那麽,對於 Whoosh 是十分容易上手的。

    按照筆者的理解以及 Whoosh 的官方文件,Whoosh 的入門使用主要是 index 以及 query。搜尋引擎的強大功能之一在於它能夠提供全文檢索,這依賴於排序演算法,比如 BM25,也依賴於我們怎樣儲存欄位。因此,index 作為名詞時,是指欄位的索引,index 作為動詞時,是指建立欄位的索引。而 query 會將我們需要查詢的語句,透過排序演算法,給出合理的搜尋結果。

    關於 Whoosh 的使用,在官文文件中已經給出了詳細的說明,筆者在這裏只給出一個簡單的例子,來說明 Whoosh 如何能方便地提升我們的搜尋體驗。

    # 範例程式碼

    數據

    本計畫的範例數據為 poem.csv,下圖為該數據集的前十行:

    圖片
    poem.csv

    欄位

    根據數據集的特征,我們建立四個欄位(fields):title, dynasty, poet, content。建立的程式碼如下:

    # -*- coding: utf-8 -*-
    import os
    from whoosh.index import create_in
    from whoosh.fields import *
    from jieba.analyse import ChineseAnalyzer
    import json
    # 建立schema, stored為True表示能夠被檢索
    schema = Schema(title=TEXT(stored=True, analyzer=ChineseAnalyzer()),
    dynasty=ID(stored=True),
    poet=ID(stored=True),
    content=TEXT(stored=True, analyzer=ChineseAnalyzer())
    )

    其中,ID 只能為一個單元值,不能分割為若幹個詞,常用於檔路徑、URL、日期、分類;
    TEXT 檔的文本內容,建立文本的索引並儲存,支持詞匯搜尋;Analyzer 選擇結巴中文分詞器。

    建立索引檔

    接著,我們需要建立索引檔。我們利用程式先解析 poem.csv 檔,並將它轉化為 index,寫入到 indexdir 目錄下。Python 程式碼如下:

    # 解析poem.csv檔
    with open('poem.csv''r', encoding='utf-8'as f:
    texts = [_.strip().split(','for _ in f.readlines() if len(_.strip().split(',')) == 4]
    # 儲存schema資訊至indexdir目錄
    indexdir = 'indexdir/'
    ifnot os.path.exists(indexdir):
    os.mkdir(indexdir)
    ix = create_in(indexdir, schema)
    # 按照schema定義資訊,增加需要建立索引的文件
    writer = ix.writer()
    for i in range(1, len(texts)):
    title, dynasty, poet, content = texts[i]
    writer.add_document(title=title, dynasty=dynasty, poet=poet, content=content)
    writer.commit()

    index 建立成功後,會生成 indexdir 目錄,裏面含有上述 poem.csv 數據的各個欄位的索引檔。

    查詢

    index 建立成功後,我們就利用進行查詢。
    比如我們想要查詢 content 中含有 明月 的詩句,可以輸入以下程式碼:

    # 建立一個檢索器
    searcher = ix.searcher()
    # 檢索content中出現'明月'的文件
    results = searcher.find("content""明月")
    print('一共發現%d份文件。' % len(results))
    for i in range(min(10, len(results))):
    print(json.dumps(results[i].fields(), ensure_ascii=False))

    輸出結果如下:

    一共發現44份文件。
    前10份文件如下:
    {"content""床前明月光,疑是地上霜。舉頭望明月,低頭思故鄉。""dynasty""唐代""poet""李白 ""title""靜夜思"}
    {"content""邊草,邊草,邊草盡來兵老。山南山北雪晴,千裏萬裏月明。明月,明月,胡笳一聲愁絕。""dynasty""唐代""poet""戴叔倫 ""title""調笑令·邊草"}
    {"content""獨坐幽篁裏,彈琴復長嘯。深林人不知,明月來相照。""dynasty""唐代""poet""王維 ""title""竹裏館"}
    {"content""漢江明月照歸人,萬裏秋風一葉身。休把客衣輕浣濯,此中猶有帝京塵。""dynasty""明代""poet""邊貢 ""title""重贈吳國賓"}
    {"content""秦時明月漢時關,萬裏長征人未還。但使龍城飛將在,不教胡馬度陰山。""dynasty""唐代""poet""王昌齡 ""title""出塞二首·其一"}
    {"content""京口瓜洲一水間,鐘山只隔數重山。春風又綠江南岸,明月何時照我還?""dynasty""宋代""poet""王安石 ""title""泊船瓜洲"}
    {"content""四顧山光接水光,憑欄十裏芰荷香。清風明月無人管,並作南樓一味涼。""dynasty""宋代""poet""黃庭堅 ""title""鄂州南樓書事"}
    {"content""青山隱隱水迢迢,秋盡江南草未雕。二十四橋明月夜,玉人何處教吹簫?""dynasty""唐代""poet""杜牧 ""title""寄揚州韓綽判官"}
    {"content""露氣寒光集,微陽下楚丘。猿啼洞庭樹,人在木蘭舟。廣澤生明月,蒼山夾亂流。雲中君不見,竟夕自悲秋。""dynasty""唐代""poet""馬戴 ""title""楚江懷古三首·其一"}
    {"content""海上生明月,天涯共此時。情人怨遙夜,竟夕起相思。滅燭憐光滿,披衣覺露滋。不堪盈手贈,