小编典典

如何提供更准确的搜索结果?

all

我正在尝试为 Web 应用程序实现搜索栏。我目前拥有的是一个接收 a 的输入,String然后我尝试将其标记为一个Array对象String,如下所示:

function tokenize(string: string) {
  string = string.replace(/[\W_]/g, ' ');
  string = string.replace(/\s\s+/g, ' ');

  const tokens: string[] = [];
  string.split(' ').forEach((element) => element && tokens.push(element));

  return tokens;
}

我最终得到的是一个Array包含用户提供的搜索词的。我不包括任何非单词字符,因为它们在这种情况下通常不重要。这些是给定包含非单词字符的输入时tokenize函数将返回的一些示例:

输入:"Zero 7 - Give It Away"
输出:[ "zero", "7", "give", "it", "away" ]

输入:"Thievery Corporation - Claridad (feat. Natalia Clavier)"
输出:[ "thievery", "corporation", "claridad", "feat", "natalia", "clavier" ]

我的下一步行动是遍历返回值的每个元素并将它们与可用轨道的标题(包含轨道数据的对象)进行比较,以查看该元素是否是任何标题的一部分(可能通过正则表达式)。

如果这是真的,那么我会将该特定曲目附加到搜索结果中。否则,我将继续比较现在标记化的对象的下一个元素ArrayString直到每个搜索词都经过测试。

我对这种方法的问题是它不能提供我理想中想要的准确性。例如,艺术家Zero 7有多首曲目。起初,这将返回他们创建的任何曲目 - 这正是人们所期望的,但如果用户提供更多搜索词怎么办?

例如,用户可以在搜索栏中键入“zero 7 - give”,这将返回Zero 7的任何曲目。实际上,它甚至没有那么精确,因为“零”这个词和数字“7”也会被测试用于其他轨道——“给予”这个词也是如此。

这是我遇到的一个问题,因为我不知道如何以提供更准确搜索结果的方式应用我的标记化值。请注意,我不是在关注任何代码,而是对促进准确搜索结果所需的步骤进行分解(至少比我目前可以提供的更好)。

我的目标是在搜索结果方面稍微灵活但准确。我仍然希望搜索词“零”和“7”返回该艺术家的任何曲目。然而,更精确的搜索,如“零”、“7”和“给予”,理想情况下应该只返回同一艺术家的曲目,其标题中也有“给予”。

如果可以确定艺术家,我不想将“给予”与任何其他曲目匹配 - 这是完全可能的,因为每首曲目都包含制作该曲目的艺术家的姓名。这就是我的创造力陷入僵局的地方,因为我似乎无法将这些碎片拼凑在一起。

任何帮助将不胜感激。我从未创建过更高级的搜索栏,但我想提高我在这方面的知识。我认为数据都在那里,但是缺乏方法。


阅读 62

收藏
2022-07-09

共1个答案

小编典典

基本上,您正在寻找的是相关性评分(或“排名功能”)。我们的想法是,我们根据关键字为每个“文档”(在您的情况下为曲目名称)分配一些数字“分数”,并按其分数排序显示文档。

为了计算最简单的排名函数,我们将文档中出现的每个关键字的分数加 1:

for (doc of documents)
   doc.score = keywords.reduce((score, kw) => score + doc.includes(kw))
documents.sort(...by score, reversed...)

所以如果有 5 个关键字,包含所有 5 个关键字的文档得分为 5,不包含任何关键字的文档得分为 0。

这种方法有很多可能的改进。例如,您可以将非常常见的单词(如“the”)赋予比稀有单词更低的优先级。为此,您需要为每个关键字计算所谓的 IDF,即文档总数除以包含该关键字的文档数,然后将关键字的 IDF 添加到总分中,而不仅仅是 1。

另一个想法是利用包含特定顺序的关键字的文档,例如,当搜索“red socks”时,“blue shirt and red socks”之类的文档将比“blue socks and red dress”之类的文档排名更高。为此,您首先计算“n-gram”(关键字序列)的分数,如果找不到任何内容,则求助于单个关键字。

2022-07-09