【问题标题】:Find most repeated phrase on huge text在大文本中查找重复次数最多的短语
【发布时间】:2015-06-27 12:24:20
【问题描述】:

我有大量的文本数据。我的整个数据库都是 UTF-8 的文本格式

我需要在我的整个文本数据中列出最重复的短语。

例如我的愿望输出是这样的:

{
  'a': 423412341,
  'this': 423412341,
  'is': 322472341,
  'this is': 222472341,
  'this is a': 122472341,
  'this is a my': 5235634
}

处理和存储每个短语占用大量数据库。 例如存储在 MySQL 或 MongoDB 中。 问题是有没有更有效的数据库或算法来找到这个结果? Solr、Elasticsearch 等...

我认为每个短语中最多 10 个单词对我有好处。

【问题讨论】:

  • 我建议在您的短语中包含最多字数。

标签: search text full-text-search bigdata


【解决方案1】:

Amy Tavori 的最佳答案是:

显然,长度为 l + 1 的最常用词组必须包含长度为 l 的最常用词组作为前缀,因为将单词附加到词组并不能增加其流行度。

虽然将单词附加到短语中确实不能增加其受欢迎程度,但没有理由假设 2-gram 的频率受 1-gram 的频率的限制。为了说明这一点,请考虑以下语料库(专门构建以说明这一点):

在这里,将存在一个棘手的语料库;一个非常奇怪的、有时神秘的语料库可能会让你目瞪口呆,也许有点;特别是因为我狡猾的语料库与您期望的模式不匹配;它也不会像鱼、船、向日葵或非常英俊的小猫。这个棘手的语料库会让一个名叫 Ami Tavory 的用户大吃一惊。这个棘手的语料库在一年、一个月或一分钟后会很有趣。

查看最常见的单个单词,我们得到:

1-Gram  Frequency
------  ---------
a       12
will    6
corpus  5
tricksy 4
or      3
from    2
it      2
the     2
very    2
you     2

Ami Tavori 建议的方法将识别顶部的 1-gram,“a”,并将搜索范围缩小到带有前缀“a”的 2-gram。但是从之前的语料来看,前 2-gram 是:

2-Gram          Frequency
------          ---------
corpus will     5
tricksy corpus  4
or a            3
a very          2

继续 3-gram,整个语料库中只有一个重复的 3-gram,即:

3-Gram                Frequency
------                ---------
tricksy corpus will   4

概括:您不能使用顶部 m-gram 直接推断顶部 (m+1)-gram。你能做的就是扔掉底部的 m-gram,特别是那些根本不重复的,然后查看所有重复的 m-gram。这会缩小范围。

【讨论】:

    【解决方案2】:

    将其标记为 1 到 10 个单词 并按标记长度插入到 10 个 SQL 表中。确保在带有字符串标记的列上使用哈希索引。然后只需在每个表上调用SELECT token,COUNT(*) FROM tablename GROUP BY token 并将结果转储到某处并等待。

    编辑:这对于大型数据集是不可行的,仅对于每个 N-gram 将计数更新 +1 或将新行插入表中(在 MYSQL 中将是有用的查询 INSERT...ON DUPLICATE KEY UPDATE)。不过,您绝对应该仍然使用哈希索引。

    之后,只需按出现次数排序并合并这 10 个表中的数据(您可以一步完成,但这会给内存带来更多压力)。

    警惕 Ami Tavory 建议的启发式方法,如果选择错误的参数,可能会得到错误的结果(在一些经典术语或短语上可以看到采样算法的缺陷 - 例如“人身保护令” - 既不是人身保护也不是语料库将被自己选择为频繁,但作为一个 2 个单词的短语,它的排名可能比您通过附加/前置到常用单词中获得的某些短语的排名更高)。当然没有必要将它们用于长度较短的标记,只有在经典方法失败时才可以使用它们(占用太多时间或内存)。

    【讨论】:

      【解决方案3】:

      您是否考虑过使用MapReduce

      假设您可以访问适当的基础架构,这似乎很适合它。您将需要一个分词器,将行拆分为最多 10 个词的多词分词。我不认为这有什么大不了的。 MR 作业的结果将是 token -> frequency 对,您可以将其传递给另一个作业以按频率对它们进行排序(一个选项)。我建议在考虑其他解决方案之前阅读 Hadoop/MapReduce。您也可以使用 HBase 来存储任何中间输出。

      Google MapReduce 上的原始paper

      【讨论】:

        【解决方案4】:

        如果您可以将数据存储在Apache Solr 中,那么Luke Request Handler 可以用于查找最常用的短语。示例查询:

        http://127.0.0.1:8983/solr/admin/luke?fl=fulltext&numTerms=100
        

        此外,Terms Component 可能有助于找到最常见的单词。这是一篇关于 Self Updating Solr Stopwords 的文章,它使用术语组件查找 100 个最常见的索引词并将它们添加到停用词文件中。示例查询:

        http://127.0.0.1:8983/solr/terms?terms.fl=fulltext&terms.limit=100
        

        【讨论】:

          【解决方案5】:

          这可以大大简化。你根本不需要数据库。只需将全文存储在文件中即可。然后编写一个 PHP 脚本来打开和读取文件内容。使用 PHP 正则表达式函数提取匹配项。将总数保存在全局变量中。将结果写入另一个文件。而已。

          【讨论】:

          • 问题是缩放...大文本不适用于这些类型的操作
          • 缩放?真的吗?您是否实时执行此计算?我希望不是。即使你是,你也可以在它之上构建一个缓存层。它不像“巨大的文本”变化。另外,定义大文本。我们在这里谈论多少个角色?无论您使用哪种类型的数据存储,都必须将数据读入内存才能对其进行分析。因此,在这种情况下,使用数据库没有任何价值,因为“LIKE”系统不会收集您需要的数据。
          • 更进一步,您的问题并未提及任何可扩展性要求。但如果确实如此,运行 HHVM 的体面的 Linux 机器将像当今可用的任何顶级平台解决方案一样快速地分析文本。唯一可以与 HHVM 竞争的平台是 Node.js 或 GO。
          【解决方案6】:

          我建议结合两个领域的想法,这里:Streaming AlgorithmsApriori Algorithm From Market-Basket Analysis

          1. 让我们从不将整个语料库加载到内存中的情况下找到 k 个最频繁的单个单词的问题开始。一个非常简单的算法,Sampling(参见Finding Frequent Items in Data Streams])可以很容易地做到这一点。此外,它非常适合并行实现(如下所述)。有大量关于 top-k 查询的工作,包括一些分布式版本(参见,例如,Efficient Top-K Query Calculation in Distributed Networks)。

          2. 现在来解决k 个最常见短语(可能是多个短语)的问题。显然,长度为 l + 1 的最常用短语必须包含长度为 l 的最常用短语作为前缀,因为将单词附加到短语并不能增加其流行度。因此,一旦你有了 k 个最常用的单个词,你就可以只扫描语料库中的它们(这样更快)来构建长度为 2 的最频繁的短语。使用它,你可以构建最长度为 3 的常用短语,依此类推。停止条件是当一个长度为 l + 1 的短语不驱逐任何长度为 l 的短语时。


          采样算法的简短描述

          这是一个非常简单的算法,它将以很高的概率从频率至少为 f 的项目中找到前 k 个项目。它分两个阶段运行:第一个阶段找到候选元素,第二个阶段对它们进行计数。

          在第一阶段,从语料库中随机选择~log(n)/f个词(注意这个比n少很多)。很有可能,您想要的所有单词都出现在这些单词的集合中。

          在第二阶段,维护一个包含这些候选元素计数的字典;扫描语料库,统计出现次数。

          输出第二阶段产生的前k项。

          请注意,第二阶段非常适合并行实施。如果将文本划分为不同的段,并计算每个段中出现的次数,则可以轻松地在末尾组合字典。

          【讨论】:

          • 好答案...我想起来似乎很好...我需要知道对于像 Solr 或 ElasticSearch 这样的全文搜索数据库没有替代解决方案?我认为 MongoDB 是该算法的最佳选择。
          • 谢谢。如果您的整个数据库都是文本形式,我不会使用这些工具中的任何一个,而是直接使用某种编程语言来实现上述内容。例如,MongoDB 会给你什么?
          • Here 是一个关于 solr 的 SO 问题(有限版本)。正如您在 cmets 中看到的那样,它可能会很慢。我建议直接编程。
          • 不错的方法,但 Apriori 算法并不适用,如此处所述;前 1-gram 不一定是前 2-gram 的一部分,也不一定是 any 重复的 2-gram 的一部分。你只能说任何频率为 f 的 n-gram 必须包含一个前缀(和一个后缀),它是一个至少频率为 f 的 (n-1)-gram。
          猜你喜欢
          • 1970-01-01
          • 2013-11-06
          • 1970-01-01
          • 1970-01-01
          • 2011-12-19
          • 1970-01-01
          • 1970-01-01
          • 2013-06-24
          • 1970-01-01
          相关资源
          最近更新 更多