我有一个大文本文档,我有一个搜索查询(例如:攀岩)。我想从文本中返回5个最相关的句子。有哪些方法可以遵循?我是这个文本检索领域的新手,所以任何帮助都表示赞赏。
我能想到的一种方法是: 逐句扫描文件,在句子中查找整个搜索查询,如果匹配则返回句子。
上述方法只有在某些句子包含整个搜索查询时才有效。如果没有包含整个查询的句子,并且某些句子只包含其中一个单词,该怎么办?或者如果它们不包含任何单词怎么办? 有什么帮助吗?
我的另一个问题是我们可以预处理文本文档以使建筑索引更容易吗?是否是预处理的良好数据结构?
答案 0 :(得分:5)
通常,相关性是您使用某种评分函数定义的。我将举例说明一个天真的评分算法,以及一个常见的搜索引擎排名算法(用于文档,但我为了教育目的将其修改为句子)。
这是一个天真排名算法的例子。排名可以简单:
BM25是一种很好的健壮算法,用于对与查询相关的文档进行评分。出于参考目的,这是一篇关于BM25 ranking algorithm的维基百科文章。您可能希望稍微修改它,因为您正在处理句子,但您可以采用类似的方法将每个句子视为“文档”。
在这里。假设您的查询包含关键字q 1 ,q 2 ,...,q m ,句子的分数 S < / strong>关于查询 Q 的计算方法如下:
SCORE(S,Q)= SUM(i = 1..m)(IDF(q i * f(q i ,S)*(k < sub> 1 + 1)/(f(q i ,S)+ k 1 *(1 - b + b * | S | / AVG_SENT_LENGTH) )
k 1 和b是自由参数(可以在[1.2,2.0]中选择k并且b = 0.75 - 你可以凭经验找到一些好的值)f(q i ,S)是一句话 S 中q i 的术语频率(可以视为该术语出现的次数),| S |是句子的长度(以单词表示),AVG_SENT_LENGTH是文档中句子的平均句子长度。最后,IDF(q i )是q i 的逆文档频率(或者,在这种情况下,是反向句子频率),通常计算如下: p>
IDF(q i )= log((N - n(q i )+ 0.5)/(n(q i ) + 0.5))
其中 N 是句子总数,n(q i )是包含q i 的句子数。
假设您不存储反向索引或任何其他数据结构以便快速访问。 这些是可以预先计算的术语: N ,* AVG_SENT_LENGTH *。
首先,请注意匹配的术语越多,这句话的得分就越高(因为总和术语)。因此,如果您从查询中获得顶级 k 项,则您确实需要计算值f(q i ,S),| S |和n(q i ),这将花费O(AVG_SENT_LENGTH * m * k)
,或者如果您在最坏的情况下对所有句子进行排名,O(DOC_LENGTH * m)
时间 k 是文档的数量匹配的术语数最多且 m 的是查询术语的数量。假设每个句子都是AVG_SENT_LENGTH,你必须为每个 k 句子去 m 次。
现在让我们看看inverted index以允许快速文本搜索。我们会将您的句子视为教育目的的文件。我们的想法是为BM25计算构建一个数据结构。我们需要使用反向列表存储术语频率:
word i :( sent_id 1 ,tf 1 ),(sent_id 2 ,tf 2 ),...,(sent_id k ,tf k )
基本上,您的密钥为word
的哈希映射,而您的值是对应于句子ID和单词频率的对(sent_id<sub>j</sub>, tf<sub>k</sub>)
列表。例如,它可能是:
摇滚:( 1,1),(5,2)
这告诉我们单词rock出现在第一句中1次,第5句出现2次。
此预处理步骤可让您O(1)
访问任何特定字词的字词频率,因此您可以根据需要快速访问。
另外,你想要另一个hashmap来存储句子长度,这应该是一个相当容易的任务。
如何构建倒排索引?我在你的案例中跳过词干和词形还原,但欢迎你阅读更多关于它的内容。简而言之,您遍历文档,不断为包含单词的hashmap创建成对/增加频率。以下是构建索引的slides。