最近折騰索引引擎以及數(shù)據(jù)統(tǒng)計方面的工作比較多, 與 Python 字典頻繁打交道, 至此整理一份此方面 API 的用法與坑法備案.
索引引擎的基本工作原理便是倒排索引, 即將一個文檔所包含的文字反過來映射至文檔; 這方面算法并沒有太多花樣可言, 為了增加效率, 索引數(shù)據(jù)盡可往內存里面搬, 此法可效王獻之習書法之勢, 只要把十八臺機器內存全部塞滿, 那么基本也就功成名就了. 而基本思路舉個簡單例子, 現(xiàn)在有以下文檔 (分詞已經(jīng)完成) 以及其包含的關鍵詞
doc_a: [word_w, word_x, word_y] doc_b: [word_x, word_z] doc_c: [word_y]
將其變換為
word_w -> [doc_a] word_x -> [doc_a, doc_b] word_y -> [doc_a, doc_c] word_z -> [doc_b]
寫成 Python 代碼, 便是
doc_a = {'id': 'a', 'words': ['word_w', 'word_x', 'word_y']} doc_b = {'id': 'b', 'words': ['word_x', 'word_z']} doc_c = {'id': 'c', 'words': ['word_y']} docs = [doc_a, doc_b, doc_c] indices = dict() for doc in docs: for word in doc['words']: if word not in indices: indices[word] = [] indices[word].append(doc['id']) print indices
不過這里有個小技巧, 就是對于判斷當前詞是否已經(jīng)在索引字典里的分支
if word not in indices: indices[word] = []
可以被 dict 的 setdefault(key, default=None) 接口替換. 此接口的作用是, 如果 key 在字典里, 那么好說, 拿出對應的值來; 否則, 新建此 key , 且設置默認對應值為 default . 但從設計上來說, 我不明白為何 default 有個默認值 None , 看起來并無多大意義, 如果確要使用此接口, 大體都會自帶默認值吧, 如下
for doc in docs: for word in doc['words']: indices. setdefault(word, []) .append(doc['id'])
這樣就省掉分支了, 代碼看起來少很多.
不過在某些情況下, setdefault 用起來并不順手: 當 default 值構造很復雜時, 或產(chǎn)生 default 值有副作用時, 以及一個之后會說到的情況; 前兩種情況一言以蔽之, 就是 setdefault 不適用于 default 需要惰性求值的場景. 換言之, 為了兼顧這種需求, setdefault 可能會設計成
def setdefault(self, key, default_factory): if key not in self: self[key] = default_factory() return self[key]
倘若真如此, 那么上面的代碼應改成
for doc in docs: for word in doc['words']: indices.setdefault(word, list ).append(doc['id'])
新聞熱點
疑難解答