在这篇文章中,我将分享一次关于设计文档搜索引擎的面试经验。这道题目需要我们实现一个简单的文档搜索引擎,并计算每个文档相对于查询的相关性评分。下面是对这道题目的详细分析和解题思路。
题目描述
我们需要构建一个文档搜索引擎,该引擎接受一组静态文档列表——由字母数字、小写和空格分隔的字符串组成。例如:
['this is a document', 'this is another document']
搜索引擎只需支持字母数字、小写和空格分隔的查询。例如:
'some query'
我们需要向用户暴露一个函数:
searchDocuments(query: string)
该函数返回一个搜索结果列表,每个结果包含文档索引和相关性评分。搜索结果按相关性评分从高到低排序。如果文档与查询完全不匹配,则不应包含在搜索结果中。
例如,调用 searchDocuments
,传入 some query
可能返回如下结果:
[{ index: 5, score: 2.828 }, { index: 1, score: 1.414 }]
评分机制
文档评分基于以下三个组件:
- tf(词频):term frequency = sqrt(词在文档中出现的次数)
- 直觉:如果某个词频繁出现,则文档更有可能与该词相关。
- idf(逆文档频率):inverse document frequency = 1 + log(文档总数 / (包含该词的文档数 + 1))
- 直觉:我们应该对稀有词语赋予更高的权重,而对大量文档中都出现的词语赋予较低的权重。
- dn(文档长度归一化):document length norm = 1 / sqrt(文档中的词语数)
- 直觉:如果文档可以任意长,则词频的意义不大。
我们可以利用这些组件计算相关性评分:
Document score for query = sum((tf * idf² * dn) for each term in the query)
示例
例如,文档为:
'this is a long document about a dog and a cat'
查询为:
'dog cat dog'
则评分计算如下:
2 * (tf_for_dog * idf_for_dog² * dn_for_dog) + (tf_for_cat * idf_for_cat² * dn_for_cat)
解题思路
- 文档预处理:
- 首先遍历所有文档,计算每个词的词频(tf)、逆文档频率(idf)以及文档长度归一化因子(dn)。
- 查询处理:
- 对于每个查询,计算查询中每个词的词频(tf),并结合预处理阶段计算得到的idf和dn,计算文档的相关性评分。
- 排序和返回结果:
- 将所有文档按相关性评分从高到低排序,并返回包含文档索引和相关性评分的结果列表。
实现步骤
- 构建词频(tf):
- 对每个文档,遍历其中的每个词,计算该词在文档中出现的次数,并取平方根。
- 计算逆文档频率(idf):
- 对每个词,计算包含该词的文档数,并计算idf值。
- 文档长度归一化(dn):
- 对每个文档,计算文档中词语的总数,并取平方根的倒数。
- 查询处理和评分计算:
- 对每个查询,遍历查询中的每个词,结合文档的tf、idf和dn,计算每个文档的相关性评分。
- 排序和返回结果:
- 将所有文档按相关性评分从高到低排序,并返回结果列表。
总结
这道题目通过设计一个简单的文档搜索引擎,考察了我们对信息检索和相关性评分机制的理解和应用。在实现过程中,我们需要结合使用词频、逆文档频率和文档长度归一化因子来计算文档的相关性评分,并按评分排序返回结果。
希望这个分享对大家有所帮助,如果有任何问题或建议,欢迎在评论区留言!
通过这次面试和代码修改,候选人大大提升了在面试官面前的面试表现。我们csoahelp提供面试代面,面试辅助服务,力求提高每一位候选人的面试成功率。如果您也有兴趣,欢迎联系我们。