[Whoosh 搜索引擎之 四 ] 模式設(shè)計

模式設(shè)計

關(guān)于模式和字段

模式指定索引中文檔的字段悔橄。

每個文檔可以有多個字段,比如標題腺毫、內(nèi)容、url挣柬、日期等潮酒。

一些字段可以被索引,一些字段可以與文檔一起存儲邪蛔,以便字段值在搜索結(jié)果中可用急黎。一些字段將被索引和存儲。

模式是文檔中所有可能字段的集合侧到。每個單獨的文檔可能只使用模式中可用字段的一個子集勃教。

例如,用于索引電子郵件的簡單模式可能包含 from_addr匠抗、to_addr故源、subjectbodyattachments 等字段 汞贸,其中 attachments 字段列出了電子郵件附件的名稱绳军。對于沒有附件的電子郵件,您可以省略附件字段矢腻。

內(nèi)置字段類型

Whoosh 提供了一些有用的預(yù)定義字段類型:

whoosh.fields.TEXT
這種類型用于正文门驾。它索引(并可選地存儲)文本并存儲術(shù)語位置以允許短語搜索。

TEXT 字段默認使用 StandardAnalyzer 分析器多柑。要指定不同的分析器奶是,請在構(gòu)造函數(shù)中使用 analyzer 參數(shù),例如 TEXT(analyzer=analysis.StemmingAnalyzer()). 請參閱 關(guān)于分析器

默認情況下聂沙,TEXT 字段存儲每個索引術(shù)語的位置信息秆麸,以允許您搜索短語。如果您不需要能夠在文本字段中搜索短語逐纬,您可以關(guān)閉存儲術(shù)語位置以節(jié)省空間蛔屹。使用 TEXT(phrase=False)

默認情況下豁生,TEXT 不存儲字段兔毒。通常您不想將正文存儲在搜索索引中。通常您可以根據(jù)搜索結(jié)果閱讀或鏈接到索引文檔本身甸箱,因此您不需要將它們的文本存儲在搜索索引中育叁。但是,在某些情況下它可能很有用(請參閱 如何創(chuàng)建突出顯示的搜索結(jié)果摘錄)芍殖。使用 TEXT(stored=True) 指定將文本存儲在索引中豪嗽。

whoosh.fields.KEYWORD
此字段類型專為以空格或逗號分隔的關(guān)鍵字而設(shè)計。這種類型是索引和可搜索的(并且可以選擇存儲)豌骏。為了節(jié)省空間龟梦,它不支持短語搜索。

要將字段的值存儲在索引中窃躲,請在構(gòu)造函數(shù)中使用 stored=True 计贰。要在索引關(guān)鍵字之前自動將關(guān)鍵字小寫,請使用 lowercase=True.

默認情況下蒂窒,關(guān)鍵字以空格分隔躁倒。要改為用逗號分隔關(guān)鍵字(以允許關(guān)鍵字包含空格),請使用 commas=True.

如果您的用戶需要使用 KEYWORD 字段進行搜索洒琢,請使用 scorable=True.

whoosh.fields.ID
字段 ID 類型只是將字段的整個值作為一個單元進行索引(并可選地存儲)也就是說秧秉,它不會將其分解為單獨的術(shù)語。這種類型的字段不存儲頻率信息衰抑,因此它非常緊湊象迎,但對于評分不是很有用。

ID 用于 URL 或路徑(文檔的 URL 或文件路徑)呛踊、日期挖帘、類別等字段,這些字段的值必須作為一個整體來處理恋技,并且每個文檔只能有一個值使用此類型拇舀。

默認情況下,ID 字段不存儲蜻底。使用 ID(stored=True) 指定字段的值應(yīng)與文檔一起存儲以用于搜索結(jié)果骄崩。例如聘鳞,您可能希望存儲 URL 字段的值,以便您可以在搜索結(jié)果中提供指向原始內(nèi)容的鏈接要拂。

whoosh.fields.STORED
該字段與文檔一起存儲抠璃,但未編入索引且不可搜索。這對于您希望在搜索結(jié)果中向用戶顯示但不需要能夠搜索到的文檔信息很有用脱惰。

whoosh.fields.NUMERIC
該字段以緊湊搏嗡、可排序的格式存儲整數(shù)、長整數(shù)或浮點數(shù)拉一。

whoosh.fields.DATETIME
該字段以緊湊采盒、可排序的格式存儲日期時間對象。

whoosh.fields.BOOLEAN
這個簡單的字段索引布爾值并允許用戶搜索 yes, no, true, false, 1, 0,tf蔚润。

whoosh.fields.NGRAM
待定磅氨。

專家用戶可以創(chuàng)建自己的字段類型。

創(chuàng)建模式

創(chuàng)建一個模式:

from whoosh.fields import Schema, TEXT, KEYWORD, ID, STORED
from whoosh.analysis import StemmingAnalyzer

schema = Schema(from_addr=ID(stored=True),
                to_addr=ID(stored=True),
                subject=TEXT(stored=True),
                body=TEXT(analyzer=StemmingAnalyzer()),
                tags=KEYWORD)

如果您不需要為預(yù)定義字段構(gòu)造函數(shù)指定任何參數(shù)嫡纠,則可以省略括號(例如烦租,使用 fieldname=TEXT 替代 fieldname=TEXT())。Whoosh 將為您實例化該類除盏。

或者叉橱,您可以使用 SchemaClass 基類以聲明方式創(chuàng)建模式:

from whoosh.fields import SchemaClass, TEXT, KEYWORD, ID, STORED

class MySchema(SchemaClass):
    path = ID(stored=True)
    title = TEXT(stored=True)
    content = TEXT
    tags = KEYWORD

您可以將聲明類傳遞給實例 create_in()create_index() 代替 Schema 實例。

索引后修改架構(gòu)

創(chuàng)建索引后者蠕,您可以使用 add_field()remove_field() 方法向模式添加或刪除字段赏迟。這些方法在 Writer 對象上:

writer = ix.writer()
writer.add_field("fieldname", fields.TEXT(stored=True))
writer.remove_field("content")
writer.commit()

(如果您要修改模式并使用同一編寫器添加文檔,則必須在添加任何文檔之前調(diào)用 add_field()remove_field

為了方便起見蠢棱,這些方法也在 Index 對象上,但是當(dāng)您在 Index 上調(diào)用它們時 甩栈,Index 對象只是創(chuàng)建編寫器泻仙,在其上調(diào)用相應(yīng)的方法,然后提交量没,因此如果您想要添加或刪除多個字段玉转,自己創(chuàng)建編寫器效率更高:

ix.add_field("fieldname", fields.KEYWORD)

filedb 后端,刪除字段只是簡單的從架構(gòu)中刪除該字段 —— 索引不會變小殴蹄,有關(guān)該字段的數(shù)據(jù)將保留在索引中究抓,直到您進行優(yōu)化。優(yōu)化將壓縮索引袭灯,同時刪除對已刪除字段的引用:

writer = ix.writer()
writer.add_field("uuid", fields.ID(stored=True))
writer.remove_field("path")
writer.commit(optimize=True)

因為數(shù)據(jù)是以字段名存儲在磁盤上的刺下,所以在沒有優(yōu)化中間索引的情況下,不要添加與已刪除字段同名的新字段:

writer = ix.writer()
writer.delete_field("path")
# 不要這樣做;i佘浴!
writer.add_field("path", fields.KEYWORD)

(Whoosh 的未來版本可能會自動防止此錯誤。)

動態(tài)字段

動態(tài)字段讓您可以將字段類型與任意 "glob"(包含*畅卓、?擅腰、/[abc] 等通配符的名稱)類型字段相匹配翁潘。

您可以使用 add() 方法將動態(tài)字段添加到 glob 關(guān)鍵字設(shè)置為 True 的新模式:

schema = fields.Schema(...)
# 任何以 "_d" 結(jié)尾的字段名趁冈,都將被存儲為 DATETIME 類型
schema.add("*_d", fields.DATETIME(stored=True), glob=True)

要在現(xiàn)有索引上設(shè)置動態(tài)字段,與添加常規(guī)字段相同拜马,使用 IndexWriter.add_field 方法渗勘,但 glob 關(guān)鍵字參數(shù)需要設(shè)置為 True

writer = ix.writer()
writer.add_field("*_d", fields.DATETIME(stored=True), glob=True)
writer.commit()

要刪除動態(tài)字段,請對以 glob 作為名稱的字段使用 IndexWriter.remove_field() 方法 :

writer = ix.writer()
writer.remove_field("*_d")
writer.commit()

例如一膨,要允許文檔包含以 _id 結(jié)尾的任何字段名稱并將其與 ID 字段類型相關(guān)聯(lián):

schema = fields.Schema(path=fields.ID)
schema.add("*_id", fields.ID, glob=True)

ix = index.create_in("myindex", schema)

w = ix.writer()
w.add_document(path=u"/a", test_id=u"alfa")
w.add_document(path=u"/b", class_id=u"MyClass")
# ...
w.commit()

qp = qparser.QueryParser("path", schema=schema)
q = qp.parse(u"test_id:alfa")
with ix.searcher() as s:
    results = s.search(q)

高級模式設(shè)置

字段提升 (Field boosts)

您可以為字段指定字段提升呀邢。這是一個乘數(shù),適用于在該字段中找到的任何術(shù)語的分數(shù)豹绪。例如价淌,要使 title 字段中的術(shù)語得分是 body 字段中術(shù)語得分的兩倍:

schema = Schema(title=TEXT(field_boost=2.0), body=TEXT)

字段類型

上面列出的預(yù)定義字段類型是 fields.FieldType 的子類。 FieldType 是一個非常簡單的類瞒津。它的屬性包含定義字段行為的信息蝉衣。

屬性 類型 描述
format fields.Format 定義字段記錄關(guān)于每個術(shù)語的信息類型,以及信息如何存儲在磁盤上巷蚪。
vector fields.Format 可選:如果已定義病毡,則為該字段存儲每個文檔的前向索引信息的格式。
scorable bool 如果為 True屁柏,則每個文檔中字段存儲在索引中的長度(術(shù)語的數(shù)量)啦膜。有點命名錯誤,因為字段長度不是所有評分所必需的淌喻。但是需要字段長度才能從 BM25F 獲得正確的結(jié)果僧家。
stored bool 如果為 True,則此字段的值存儲在索引中裸删。
unique bool 如果為 True八拱,則當(dāng)用戶在 IndexWriter 上調(diào)用 document_update() 時,此字段的值可用于替換具有相同值的文檔涯塔。

大多數(shù)預(yù)定義字段類型的構(gòu)造函數(shù)都具有可讓您自定義這些部分的參數(shù)肌稻。例如:

  • 大多數(shù)預(yù)定義的字段類型都可以在構(gòu)造函數(shù)中使用 FieldType.stored 參數(shù)。
  • TEXT() 構(gòu)造函數(shù)可以使用 analyzer 參數(shù)設(shè)置格式對象匕荸。

格式

對象 Format 定義字段記錄關(guān)于每個術(shù)語的信息類型爹谭,以及信息如何在磁盤上存儲。

例如榛搔,Existence 格式將存儲這樣的帖子 (postings):

Doc
10
20
30

Positions 格式將存儲這樣的帖子:

Doc Positions
10 [1,5,23]
20 [45]
30 [7,12]

索引代碼將字段的 unicode 字符串傳遞給字段的 Format 對象旦棉。該 Format 對象調(diào)用其分析器(請參閱文本分析)將字符串分解為標記齿风,然后對有關(guān)每個標記的信息進行編碼。

Whoosh 附帶以下預(yù)定義格式绑洛。

類名 描述
Stored 存儲但未索引的字段的“null”格式救斑。
Existence 只記錄詞是否在文檔中,而不存儲詞頻真屯。對于標識符字段(例如路徑或 ID)和 “tag” 類型字段很有用脸候,這些字段的頻率應(yīng)始終為 0 或 1
Frequency 存儲每個術(shù)語在每個文檔中出現(xiàn)的次數(shù)。
Positions 存儲每個術(shù)語在每個文檔中出現(xiàn)的次數(shù)以及出現(xiàn)的位置绑蔫。

STORED 字段類型使用 Stored 格式(什么都不做运沦,所以 STORED 字段沒有索引)。

類型 ID 使用 Existence 格式配深。

類型 KEYWORD 使用 Frequency 格式携添。

類型 TEXT 如果使用 phrase=True(默認值)實例化則使用 Positions 格式 ,如果 phrase=False 則使用 Frequency 格式.

此外篓叶,為方便專家用戶而實現(xiàn)了以下格式烈掠,但目前尚未在 Whoosh 中使用:

類名 描述
DocBoosts 與 Existence 類似,但額外存儲每個文檔的提升(boosts)
Characters 與 Positions 類似缸托,但額外存儲每個術(shù)語的開始和結(jié)束字符索引
PositionBoosts 與 Positions 類似左敌,但額外存儲每個位置的提升
CharacterBoosts 與 Positions 類似,但額外存儲每個術(shù)語和每個位置提升的開始和結(jié)束字符索引

向量

主索引是倒排索引俐镐。它將術(shù)語映射到它們出現(xiàn)的文檔矫限。存儲前向索引(也稱為詞向量)有時也很有用,它將文檔映射到出現(xiàn)在其中的術(shù)語佩抹。

例如叼风,想象一個字段的倒排索引:

Term Postings
apple [(doc=1, freq=2), (doc=2, freq=5), (doc=3, freq=1)]
bear [(doc=2, freq=7)]

相應(yīng)的前向索引或詞向量將是:

Doc Postings
1 [(text=apple, freq=2)]
2 [(text=apple, freq=5), (text='bear', freq=7)]
3 [(text=apple, freq=1)]

如果設(shè)置 FieldType.vector 為一個 Format 對象,索引代碼將使用該 Format 對象來存儲有關(guān)每個文檔中的術(shù)語的信息棍苹。目前默認情況下 Whoosh 根本不使用術(shù)語向量无宿,但它們可供希望實現(xiàn)自己的字段類型的專家用戶使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廊勃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子经窖,更是在濱河造成了極大的恐慌坡垫,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件画侣,死亡現(xiàn)場離奇詭異冰悠,居然都是意外死亡,警方通過查閱死者的電腦和手機配乱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門溉卓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來皮迟,“玉大人,你說我怎么就攤上這事桑寨》幔” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵尉尾,是天一觀的道長爆阶。 經(jīng)常有香客問我,道長沙咏,這世上最難降的妖魔是什么辨图? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮肢藐,結(jié)果婚禮上故河,老公的妹妹穿的比我還像新娘。我一直安慰自己吆豹,他們只是感情好鱼的,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞻讽,像睡著了一般鸳吸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上速勇,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天晌砾,我揣著相機與錄音,去河邊找鬼烦磁。 笑死养匈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的都伪。 我是一名探鬼主播呕乎,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陨晶!你這毒婦竟也來了猬仁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤先誉,失蹤者是張志新(化名)和其女友劉穎湿刽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褐耳,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡诈闺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铃芦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雅镊。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡仁烹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叙赚,到底是詐尸還是另有隱情僚饭,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站偿乖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贪薪。R本人自食惡果不足惜画切,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一霍弹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岛宦,春花似錦耍缴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荣德。三九已至,卻和暖如春鲤拿,著一層夾襖步出監(jiān)牢的瞬間署咽,已是汗流浹背宁否。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饱须,地道東北人蓉媳。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓锅铅,卻偏偏與公主長得像盐须,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子姨蟋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容