【问题标题】:Algorithm to find keywords and keyphrases in a string在字符串中查找关键字和关键短语的算法
【发布时间】:2012-06-15 20:50:12
【问题描述】:

我需要有关如何编写算法以在字符串中找到关键字或关键短语的建议或指导。

字符串包含:

  • 以英文 (GB) 编写的技术信息
  • 单词大多用空格隔开
  • 关键字不包含空格,但可以包含连字符、撇号、冒号等。
  • 关键词可以包含空格、逗号或其他标点符号
  • 如果两个或多个关键字同时出现,则很可能是关键字,例如“变频驱动”
  • 文本还包含 HTML,但如有必要,可以事先将其删除
  • 非关键字是“and”、“the”、“we”、“see”、“look”等词。
  • 关键字不区分大小写,例如“逆变器”和“逆变器”是同一个关键词

算法有如下要求:

  1. 批处理场景中操作,例如每天跑一到两次
  2. 处理长度从大约 200 到 7000 个字符不等的字符串
  3. 在 1 小时内处理 1000 个字符串
  4. 将在功率中等的服务器上执行
  5. 使用以下之一编写:C#、VB.NET 或 T-SQL 甚至可能是 F#、Python 或 Lua 等。
  6. 依赖预定义的关键字或关键词列表
  7. 但可以依赖关键字排除列表,例如“and”、“the”、“go”等
  8. 理想情况下可转移到其他语言,例如不依赖于特定语言的功能,例如元编程
  9. 输出关键词列表(频率降序)后跟关键字列表(频率降序)

如果它可以在几秒钟内处理多达 8000 个字符,这样它就可以实时运行,那就太酷了,但我已经问够了!

只是寻求建议和方向:

  • 这应该被视为两个独立的算法吗?
  • 是否有任何我可以遵循的既定算法?
  • 我的要求可行吗?

非常感谢。

附:字符串将从 SQL Server 2008 R2 数据库中检索,因此理想情况下该语言将支持此功能,如果不支持,则它必须能够读取/写入 STDOUT、管道、流或文件等。

【问题讨论】:

标签: c# sql sql-server algorithm search


【解决方案1】:

所涉及的逻辑使得在 T-SQL 中编程变得复杂。选择像 C# 这样的语言。首先尝试制作一个简单的桌面应用程序。稍后,如果您发现将所有记录加载到此应用程序太慢,您可以编写一个在 SQL-Server 上执行的 C# 存储过程。根据 SQL-Server 的安全策略,它需要有一个强密钥。


现在到算法。排除词列表通常称为停用词列表。如果您对该搜索词进行一些谷歌搜索,您可能会找到可以开始使用的停用词列表。将这些停用词添加到 HashSet<T>(我将在这里使用 C#)

// Assuming that each line contains one stop word.
HashSet<string> stopWords =
    new HashSet<string>(File.ReadLines("C:\stopwords.txt"), StringComparer.OrdinalIgnoreCase);

稍后您可以查看关键字候选是否在停用词列表中

If (!stopWords.Contains(candidate)) {
    // We have a keyword
}

HashSet 很快。它们的访问时间为 O(1),这意味着进行查找所需的时间不取决于它包含的项目数。

使用正则表达式可以轻松查找关键字。

string text = ...; // Load text from DB
MatchCollection matches = Regex.Matches(text, "[a-z]([:']?[a-z])*",
                                        RegexOptions.IgnoreCase);
foreach (Match match in matches) {
    if (!stopWords.Contains(match.Value)) {
        ProcessKeyword(match.Value); // Do whatever you need to do here
    }
}

如果您发现 a-z 对字母的限制太大并且需要重音字母,您可以将正则表达式更改为 @"\p{L}([:']?\p{L})*"。字符类\p{L} 包含所有字母和字母修饰符。

短语更复杂。您可以尝试先将文本拆分为短语,然后对这些短语应用关键字搜索,而不是在整个文本中搜索关键字。这将为您同时提供一个短语中的关键字数量。

将文本拆分为短语需要搜索以“.”结尾的句子。要么 ”?”要么 ”!”要么 ”:”。您应该排除出现在单词中的点和冒号。

string[] phrases = Regex.Split(text, @"[\.\?!:](\s|$)");

这会搜索后跟空格或行尾的标点符号。但我必须同意这并不完美。它可能会错误地将缩写词检测为句子结尾。您必须进行实验以完善拆分机制。

【讨论】:

  • 但是上面的代码不是依赖于预定义的关键字“匹配”列表吗?我希望通过算法得出关键字。
  • 不,它不包括非关键字,即所谓的停用词。所有不是停用词的都是关键字。
  • 您可以添加其他条件,例如“关键字必须至少包含 3 个字符”。您可能还希望将关键字限制为名词。查看 CodePlex 上的开源 C# 项目 SharpNLP 及其代码项目上的描述 Statistical parsing of English sentences
  • 如何在不添加所有可能变化的情况下对 HashSet 应用大小写不敏感?例如,单词“multiply”可以是:Multiply、multiply、mUltiply、MulTiply——大约 64 种变体(字母数的平方)。我认为最简单的解决方案是添加所有小写字母,然后在哈希集中使用 O(1) 查找来比较小写单词?
  • 我通过使用new HashSet&lt;string&gt;(StringComparer.OrdinalIgnoreCase);创建HashSet,使其不区分大小写
猜你喜欢
  • 1970-01-01
  • 2011-12-18
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
相关资源
最近更新 更多