我收集了大约1500份文件。我解析了每个文档并提取了令牌。这些令牌存储在散列映射(作为键)中,它们在集合中出现的总次数(即频率)将存储为值。
我必须扩展它以构建倒排索引。也就是说,术语(键)|它出现的文件数量 - > DocNo |该文件中的频率。例如,
Term DocFreq DocNum TermFreq
data 3 1 12
23 31
100 17
customer 2 22 43
19 2
目前,我在Java中有以下内容,
hashmap<string,integer>
for(each document)
{
extract line
for(each line)
{
extract word
for(each word)
{
perform some operations
get value for word from hashmap and increment by one
}
}
}
我必须以此代码为基础。我真的不能想到一个实现倒排索引的好方法。 到目前为止,我想过将值设为2D数组。因此,该术语将成为关键,而值(即2D数组)将存储docId和termFreq。
如果我的逻辑是正确的,请告诉我。
答案 0 :(得分:3)
我会使用Map<String, TermFrequencies>
来做到这一点。此映射将为找到的每个术语维护TermFrequencies对象。 TermFrequencies对象具有以下方法:
void addOccurrence(String documentId);
int getTotalNumberOfOccurrences();
Set<String> getDocumentIds();
int getNumberOfOccurrencesInDocument(String documentId);
它会在内部使用Map<String, Integer>
将术语出现的每个文档与文档中术语的出现次数相关联。
算法非常简单:
for(each document) {
extract line
for(each line) {
extract word
for(each word) {
TermFrequencies termFrequencies = map.get(word);
if (termFrequencies == null) {
termFrequencies = new TermFrequencies(word);
}
termFrequencies.addOccurrence(document);
}
}
}
addOccurrence()
方法只会增加一个计数器的总出现次数,并会插入或更新国际地图中的出现次数。
答案 1 :(得分:1)
我认为最好有两种结构:Map<docnum, Map<term,termFreq>>
和Map<term, Set<docnum>>
。您的docFreqs可以在第二张地图的值中以set.size
读取。此解决方案不涉及自定义类,并允许快速检索所需的所有内容。
第一个地图包含所有信息,第二个地图是允许按术语快速查找的衍生物。在处理文档时,您将填充第一张地图。您可以在之后派生第二张地图,但也可以一次性完成。
答案 2 :(得分:0)
我曾经实施过你所要求的东西。你的方法的问题是它不够抽象。您应该使用对象为术语,文档及其关系建模。在第一次运行中,创建术语索引和文档对象,并在填充术语索引时迭代文档中的所有术语。之后,您在内存中有一个表示,您可以轻松地转换为所需的输出。 不要首先考虑面向对象语言中的2d数组。除非你想解决数学问题或优化某些东西,否则大多数时候这不是正确的方法。
答案 3 :(得分:0)
我不知道这是否仍然是一个热门问题,但我建议你这样做:
您将遍历所有文档,并按递增顺序为其提供ID。对于每个文档,您运行所有单词。
现在你有了一个Hashmap,它将Strings(你的单词)映射到DocTermObjects数组。 DocTermObject包含docId和TermFrequency。
现在对于文档中的每个单词,你可以在HashMap中查找它,如果它不包含你创建它的DocTermObjects数组,那么你只看它的非常LAST元素(这很重要,因为运行时,想一想)。如果此元素具有您当前处理的docId,则会增加TermFrequency。否则,如果Array为空,则使用实际的docId添加新的DocTermObject,并将TermFrequency设置为1.
稍后您可以使用此数据结构来计算分数。你也可以在DoctermObjects中保存得分。
希望它有所帮助:)