【问题标题】:Counting sentences: Database (like h2) vs. Lucene vs.?计数句子:数据库(如 h2)与 Lucene 与?
【发布时间】:2011-01-17 03:31:19
【问题描述】:

我正在做一些语言研究,这取决于能够查询 1 亿个句子的语料库。我需要从该语料库中获得的信息大致如下:有多少句子有“john”作为第一个词,“went”作为第二个词,“hospital”作为第五个词......等等所以我只需要 count 并且不需要实际检索句子。

我的想法是将这些句子分成单词并将它们存储到数据库中,其中的列将是位置(word-1、word-2、word-3..etc),句子将是行。所以它看起来像:

Word1 Word2 Word3 Word4 Word5 ....

国会批准了一项新法案

约翰去上学了

.....

然后我的目的将通过调用 COUNT(SELECT * where Word1=John and Word4=school) 来实现。但我想知道:使用 Lucene(或其他工具)可以更好地实现这一点吗?

我正在编写的程序(用 Java 编写)将对该 1 亿个句子语料库进行数以万计的此类查询。所以查找速度很重要。

感谢您的建议,

阿纳斯

【问题讨论】:

    标签: java database lucene lookup performance


    【解决方案1】:

    假设查询如您所指出的那样简单,那么一个简单的 SQL 数据库(Postgres、MySQL,可能是 H2)将是完美的。

    【讨论】:

    • 这是最初的想法,但我担心(我发布此问题的部分原因)是 1 亿行的计数是否会有点慢。我的意思是,如果需要 10 秒来计算满足 select 语句的行数,那就太慢了。
    【解决方案2】:

    我想您已经拥有从给定句子创建标记的基础设施。您可以为句子中的每个单词创建一个包含一个字段的 lucene 文档。您可以将字段命名为field1, field2, 等等。由于 lucene 没有 DB 之类的模式,因此您可以根据需要动态定义任意数量的字段。如果您想识别哪些句子与查询匹配,可以添加额外的标识符字段。

    在搜索时,您的典型 lucene 查询将是

    +field1:John +field4:school
    

    由于您不关心检索速度,您可以编写一个忽略分数的自定义收集器。 (这也会显着更快地返回结果。)

    由于您不打算检索匹配的句子或单词,因此您应该只索引这些字段而不是存储。这应该会将性能提升一个档次。

    【讨论】:

      【解决方案3】:

      Lucenespan queries可以实现位置搜索。使用 SpanFirst 查找文档前 N 个位置的单词,并结合 SpanNot 排除前 N-1 个。

      您的示例查询如下所示:

      <BooleanQuery: +(+spanFirst(john, 1) +spanFirst(went, 2)) +spanNot(spanFirst(hospital, 5), spanFirst(hospital, 4))>
      

      Lucene 当然还允许在不迭代所有文档的情况下获取搜索结果的总命中数。

      【讨论】:

        【解决方案4】:
        • 我建议你阅读Search Engine versus DBMS。据我所知,您确实需要一个数据库而不是全文搜索库。
        • 无论如何,我建议您预处理文本并使用字典将每个单词/标记替换为数字。这用一组单词代码替换了每个句子。然后,我会将每个单词的位置存储在一个单独的数据库列中,从而简化计数并使其更快。 例如:

        一个男孩和一个女孩喝牛奶

        翻译成:

        120 530 14 120 619 447 253

        (我选择了任意字码)导致存储一行

        120 530 14 120 619 447 253 0 0 0 0 0 0 0 ....

        (直到你为每个句子分配的单词数用完)。

        这有点像sparse matrix,所以也许this question 会有所帮助。

        【讨论】:

        • 非常感谢您提供的链接,我发现它很有帮助。而且,实际上,我认为搜索索引器会比 DB 更快,所以我决定采用它,上帝保佑。再次感谢。
        【解决方案5】:

        查看Apache Hadoop 和 Map Reduce。它是为这样的事情而开发的。

        【讨论】:

        • MapReduce 似乎是为集群计算而设计的,我将在我的个人笔记本上做这件事(语料库只有几 GB 大小)。
        【解决方案6】:

        或者你可以手工完成,只使用 java by

        List triple = new ArrayList(3);    
        for (String word: inputFileWords) {
          if (triple.size == 3) {
              resultFile.println(StringUtils.join(" ", triple));
              triple.remove(0);
          }
          triple.add(line);
        }
        

        然后对这个文件进行排序并对所有重复的行求和(手动或从某个命令行实用程序),它会尽可能快。

        【讨论】:

        • 恐怕这对我的目的不起作用:我不只是想要重复的行,我想要满足某些属性的行数(例如有多少行有“汽车”作为第二个词和“崩溃”作为第三个词)。所以简单地折叠线条是行不通的。另外,我需要能够以相当快的方式访问该帐户,因为我的代码将执行数以万计的此类查询。
        • 哦,对不起,我只是误解了你的情况。在这种情况下,使用数据库将是最佳选择。例如,Postgres 具有一些易于索引和查询数组的功能,它可以帮助您。但是对于 1 亿行,它可能没有你希望的那么快。
        猜你喜欢
        • 1970-01-01
        • 2012-10-05
        • 2017-05-23
        • 2013-07-16
        • 2011-10-21
        • 2011-03-21
        • 1970-01-01
        • 2018-08-20
        • 2016-12-03
        相关资源
        最近更新 更多