【问题标题】:Java & Mysql processing massive dataJava & Mysql 处理海量数据
【发布时间】:2013-11-26 13:53:24
【问题描述】:

我的问题是,我有两个数据库表,一个有大约 10 000 条记录,另一个有 5 000 000 条记录,每条记录有 56 列。现在我要做的是,将这 10 000 条记录中的每条记录与另一张表中的每条记录进行比较,然后找到 10 条最佳记录(比较列值等)。 所以我正在寻找一些想法如何在合理的时间内做到这一点,因为到目前为止这将花费我太长时间...... 例如,我一直在浏览互联网并找到了 hadoop,但是我从未使用过它,而且我不确定它是否能在我的情况下完成这项工作...... 我的机器有 2 个内核和 4GB 内存,所以它不是公牛。 感谢您在合理的时间内提供任何答案

【问题讨论】:

  • 我会先将这 10,000 条记录放入内存(如果可以的话),然后遍历 500 万条记录。
  • 我不清楚为什么要比较每一个;首先对它们进行排序并仅比较第一行...
  • @user2141889 我假设您正在计算每个项目与其他项目的距离的欧几里得距离。通常这些用于基于项目的协同过滤,并且它们是离线计算的。因此,如果计算时间不超过 3-4 小时,则计算速度无关紧要。
  • @user2141889 如果花费这么多时间,您应该升级您的 mysql 版本、box 并微调 mysql,以便它处理得更快。我见过 1000 万的计算,不需要几天就可以完成。
  • @user2141889 你能改写你的问题,以便我可以发布你可以寻找微调的内容。

标签: java mysql large-data


【解决方案1】:

hadoop 的想法是它可以帮助您并行化代码执行。如果您只有一台机器,我认为 hadoop 不适合您。由于您有 2 个内核,因此您可以利用 Java 线程。

另一个限制因素是内存。基本上,如果您可以将所有记录提取到内存中,只需在开始计算之前执行此操作。如果不是这种情况(似乎 db 大小超过了您的 RAM 大小),一旦计算线程完成了一些记录,帮助线程就可以将其他记录从数据库中提取到内存中。下面是算法草图:

  • 两个 Worker 线程将并行工作(线程数 = CPU 数,因为计算密集型任务)
  • FirstArray = 在数组或 ArrayList 中加载 10.000,确保您没有使用并发结构。两个线程都会访问这个数组,但是不会改变它。 SecondArray 将由 DB Thread 提供(第 3-4 点)。两个线程的 FirstArray 将相同,SecondArray 将不同。你会有嵌套循环:

    for (elem1: FirstArray) {
        for (elem2: SecondArray){
             computeSmth(elem1, elem2)
             if (bestSoFar()) store()
        }
    }
    

一旦 Worker 线程完成,它就会向 BlockingQueue 询问下一部分数据 - 即新的 SecondArray。

  • DB 线程(实际上是第三个线程)将负责从数据库中批量获取数据并填充数组,这些数组将由工作线程进一步处理。
  • 假设第二个表中的 400.000 个元素适合内存。让我们把它分成4个区域。
    • 1 个区域将用于第一个线程正在处理的元素,
    • 2 区域将用于被第二个线程处理的元素,
    • 3 region是一个数组,等待被BlockingQueue中的一个线程占用(容量为1),
    • 4 将用于从数据库中获取的数据,但无法将其放入队列,因为其中一个工作线程未获取另一个数组。这基本上意味着 那个 DB 线程会阻塞,直到某个线程从队列中获取下一个数组,这意味着它已经完成了前一个数组并且前一个数组可以被 GC,这意味着 你不会用完内存。
  • 队列大小可能是基于最大 MySQL 批处理大小、MySQL 检索时间和工作线程在一个批处理上花费的时间的调整主题。
  • bestSoFar() 的逻辑应该经过深思熟虑,以尽量减少线程同步。
  • 基本上该算法应该可以很好地扩展(每个 CPU 可能会提供接近线性的改进)。

【讨论】:

  • 如果您有足够的内核,多线程可以为您提供足够的性能提升,花费在(多线程版本的实现 - 单线程版本的实现)上的时间可能会超过(单线程应用程序执行时间 - 多线程应用程序执行时间) .如果它是一次性任务并且代码不会被重用,这很重要
  • 感谢您的回答,它为我指明了正确的方向。
【解决方案2】:

有十几种方法可以做到这一点。这有点取决于您需要比较的内容。

一种从两个表中选择最重要列的值相同的行的方法。比对两个表中的每个匹配行进行比较。

但是,如果匹配是直接转发的(一列是否完全匹配),我会编写一个很好的 SQL 查询,返回每个行组合的匹配列数并选择前 10 个:)。

我认为,最好的策略是逐一处理 10.000 行,并尝试通过查询找到最匹配的行,并在 java 中进行附加计算以对最佳行进行排序。

理想情况下,我会为它编写一个 MapReduce 作业。但是,如果您还没有设置它,那么硬编程是您最好的其他选择。

【讨论】:

  • 我必须计算第一个表的记录和第二个表的记录之间的欧几里德距离,最好取 15,这就是为什么我认为我真的必须遍历所有记录。
  • 我现在对这个计算不太关心,但我敢打赌,你可以用 SQL 完成部分计算并进行预选。否则,制作两个表的连接产品并逐行处理它们,并将最佳 10 个匹配项保存在内存中。我假设您想要 10.000 行中的每一行中最好的 10 个。
【解决方案3】:

500 万 x 57 双倍相当于 2 GB 的 RAM。

您拥有的 4 GB 应该不是问题。

为了让事情变得更快,请使用索引。也许也可以实现自己的索引。

或在适当的地方使用排序

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 1970-01-01
    相关资源
    最近更新 更多