【问题标题】:How to efficiently extract count of each item from huge dataset?如何有效地从庞大的数据集中提取每个项目的计数?
【发布时间】:2011-12-13 17:31:26
【问题描述】:

问题如下:

  • 输入:来自维基百科的所有文章(33gb 文本)
  • 输出:SQLite 文件中来自 Wikipedia 的每个单词 skipgram(n-gram,最多 k 次跳过)的计数。

输出表架构为:

CREATE TABLE [tokens] ([token] TEXT UNIQUE NOT NULL PRIMARY KEY, [count] INTEGER  NOT NULL

天真的方法是,对于每个skipgram,我们在表中创建一个新记录或在现有记录中增加计数器:

INSERT OR REPLACE INTO [tokens] VALUES (@token, COALESCE((SELECT count FROM [tokens] WHERE token=@token), 0) + 1)

这种方法的问题是索引会不断更新,当数据库增长到几千兆时,这些更新非常慢。我们可以通过创建没有索引的“令牌”表并在处理结束时添加索引来解决这个问题。

问题在于必须扫描表的 select 语句 SELECT count FROM [tokens] WHERE token=@token 大大降低了性能。

目前我发现的最佳方法如下(我使用的是 C#):

  1. 创建Dictionary<string,int> 以计算令牌。

  2. 将标记添加到此字典,直到它变得太大而无法放入 RAM。

  3. 将字典中的标记插入(不更新)到没有索引的临时表中。该表具有以下架构:

    CREATE TABLE [temp] ([token] TEXT, [count] INTEGER)
    
  4. 如果还有更多的token,清空字典,进入第2步。

  5. 将令牌从临时表复制到令牌表:

    INSERT INTO [tokens] SELECT [token], SUM([count]) AS [count] FROM [temp] GROUP BY [token]
    

此方法“仅”需要 24 小时来处理数据集,但我认为这不是最好的方法,因为第 5 步需要 24 小时中的 22 小时。

您知道可以解决此问题的替代方法吗?

附:我的应用程序是单线程的,我在事务中分批进行上述插入(每批 100000 个)。

【问题讨论】:

    标签: c# performance algorithm sqlite


    【解决方案1】:

    我建议创建另一个具有相同定义的表,将表填充到某个状态,将结果合并到主表,清除表并开始处理下一组项目。

    【讨论】:

    • 我尝试了你的建议,但它并不能完全解决索引更新缓慢的问题,它只会降低更新频率,而每次更新都需要更多时间。几次合并后,更新变得相对较慢(合并 1000 万条记录需要十分钟)。我的数据集包含数十亿个令牌。
    • @user1096250,我还要看看sqlite临时文件调优(sqlite.org/tempfiles.html)
    【解决方案2】:

    我建议添加SET TRANSACTION ISOLATION READ UNCOMMITTED。这意味着计数可能会略有偏差,尤其是在多个尝试同时插入/更新的线程环境中。

    【讨论】:

    • 抱歉,这是针对 MS SQL 的,我没有注意到您使用的是 SQLITE
    【解决方案3】:

    如果你有很多空余的演出......

    我建议你不要边走边计算令牌,而是将所有令牌添加到一个表中并创建一个组织令牌的索引。

    CREATE TABLE tokens (token TEXT);
    CREATE INDEX tokens_token ON tokens (token ASC);
    

    然后一次添加所有令牌...

    INSERT INTO tokens VALUES ('Global Warming');
    INSERT INTO tokens VALUES ('Global Cooling');
    

    最后执行SELECT ... GROUP BY

    SELECT token, COUNT(0) token_count FROM tokens GROUP BY token
    

    【讨论】:

    • 感谢您的建议,我目前正在使用类似的方法。我将它添加到我原来的问题中。你觉得我临时表上的索引有用吗?
    【解决方案4】:

    对我来说,这听起来像是使用“计数布隆过滤器”的好地方。

    这需要对您的数据进行两次传递,这有点启发式,但应该很快。布隆过滤器允许在恒定时间内进行集合插入和存在测试。计数布隆过滤器计算找到了多少特定值,而不是只跟踪存在/不存在的通常布隆过滤器。

    【讨论】:

    • 我不能使用“计数布隆过滤器”,因为我需要查询此表的可能性,例如"select * from tokens where count>1000".
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-02
    • 2014-09-04
    • 2019-12-14
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多