在倒排索引中搜索普通查询
我有一个完整的倒排索引,它的形式是一个嵌套的Python字典。它的结构是:
{单词 : { 文档名 : [位置列表] } }
举个例子,假设这个字典叫做index,对于单词“spam”,它的条目看起来像这样:
{ spam : { doc1.txt : [102,300,399], doc5.txt : [200,587] } }
这样的话,包含任何单词的文档可以通过index[word].keys()来获取,而在该文档中单词出现的频率可以通过len(index[word][document])来计算。
现在我的问题是,如何在这个索引中实现一个普通的查询搜索。也就是说,给定一个包含4个单词的查询,找到包含所有四个单词的文档(按出现的总频率排序),然后是包含3个单词的文档,以此类推……
**
我添加了这段代码,使用了S. Lott的回答。这是我写的代码,它的工作效果正是我想要的(只是输出格式需要一些调整),但我知道它可以改进。
**
from collections import defaultdict
from operator import itemgetter
# Take input
query = input(" Enter the query : ")
# Some preprocessing
query = query.lower()
query = query.strip()
# now real work
wordlist = query.split()
search_words = [ x for x in wordlist if x in index ] # list of words that are present in index.
print "\nsearching for words ... : ", search_words, "\n"
doc_has_word = [ (index[word].keys(),word) for word in search_words ]
doc_words = defaultdict(list)
for d, w in doc_has_word:
for p in d:
doc_words[p].append(w)
# create a dictionary identifying matches for each document
result_set = {}
for i in doc_words.keys():
count = 0
matches = len(doc_words[i]) # number of matches
for w in doc_words[i]:
count += len(index[w][i]) # count total occurances
result_set[i] = (matches,count)
# Now print in sorted order
print " Document \t\t Words matched \t\t Total Frequency "
print '-'*40
for doc, (matches, count)) in sorted(result_set.items(), key = itemgetter(1), reverse = True):
print doc, "\t",doc_words[doc],"\t",count
请评论一下……谢谢。
3 个回答
在编程中,有时候我们需要处理一些数据,这些数据可能来自不同的地方,比如用户输入、文件或者网络请求。为了让程序能够理解这些数据,我们通常需要把它们转换成程序能处理的格式。
比如说,如果你从一个网页上获取了一些信息,这些信息可能是以文本的形式存在的。为了让程序能够使用这些信息,我们需要把它们转化为程序可以理解的对象或者变量。这个过程就叫做“解析”。
解析的过程就像是把一段话翻译成另一种语言,让不同的人都能理解。程序通过解析,把复杂的数据变得简单易用,这样我们就可以对这些数据进行操作,比如计算、存储或者显示。
在编程中,解析通常会用到一些特定的工具或者库,这些工具可以帮助我们快速而准确地完成这个过程。通过使用这些工具,我们可以节省很多时间和精力,让我们的程序更加高效。
import itertools
index = {...}
def query(*args):
result = []
doc_count = [(doc, len(index[word][doc])) for word in args for doc in index[word]]
doc_group = itertools.groupby(doc_count, key=lambda doc: doc[0])
for doc, group in doc_group:
result.append((doc, sum([elem[1] for elem in group])))
return sorted(result, key=lambda x:x[1])[::-1]
这里有一个找到相似文档的解决方案(这是最难的部分):
wordList = ['spam','eggs','toast'] # our list of words to query for
wordMatches = [index.get(word, {}) for word in wordList]
similarDocs = reduce(set.intersection, [set(docMatch.keys()) for docMatch in wordMatches])
wordMatches
是一个列表,里面每个元素都是一个字典,表示与某个单词匹配的文档信息。
similarDocs
是一个集合,包含了所有查询单词的文档。这是通过从 wordMatches
列表中的每个字典中提取文档名称,然后把这些文档名称转换成集合,最后找出这些集合的交集来得到的,这样就能找到共同的文档名称。
一旦找到相似的文档,你就可以使用 defaultdict(如 S. Lott 的回答中所示)将每个单词和每个文档的匹配列表合并在一起。
相关链接:
- 这个回答展示了 defaultdict(int)。defaultdict(list) 的工作方式基本相同。
- set.intersection 示例
这是一个开始:
doc_has_word = [ (index[word].keys(),word) for word in wordlist ]
这段代码会生成一个包含(单词,文档)对的列表。你不能轻易地把它变成一个字典,因为每个文档会出现很多次。
但是
from collections import defaultdict
doc_words = defaultdict(list)
for d, w in doc_has_word:
doc_words[tuple(d.items())].append(w)
这可能会有帮助。