Java 大型数据集的优化搜索技术

Java 大型数据集的优化搜索技术,java,optimization,Java,Optimization,我目前正在做一个项目,我需要处理一个大约300万行长的.csv文件和不同的.xlsx文件,这些文件的大小介于10行到1000行之间。我试图在.xlsx文件和.csv文件中找到不同单元格之间的共性。 这样做。我已读入.csv文件和.xslx文件,并将其存储在ArrayList中。 我有我想要的工作,但是我使用的方法是O(n^3),在每个循环之间使用3嵌套的for循环do搜索 //This is our .xlsx file stored in an ArrayList for(int i = 1;

我目前正在做一个项目,我需要处理一个大约300万行长的.csv文件和不同的.xlsx文件,这些文件的大小介于10行到1000行之间。我试图在.xlsx文件和.csv文件中找到不同单元格之间的共性。 这样做。我已读入.csv文件和.xslx文件,并将其存储在ArrayList中。 我有我想要的工作,但是我使用的方法是O(n^3),在每个循环之间使用3嵌套的for循环do搜索

//This is our .xlsx file stored in an ArrayList
for(int i = 1; i<finalKnowledgeGraph.size(); i+=3) {
            //loop through our knowledgeGraph again
            for(int j = 1; j<finalKnowledgeGraph.size(); j+=3) {
                //loop through .csv file which is stored in an ArrayList
                for(int k=1; k<storeAsserions.size(); k++) {
                   if(finalKnowledgeGraph.get(i).equals(storeAsserions.get(k)) && finalKnowledgeGraph.get(j+1).equals(storeAsserions.get(k+1))){
                      System.out.println("Do Something");
                   } else if(finalKnowledgeGraph.get(i+1).equals(storeAsserions.get(k)) && finalKnowledgeGraph.get(j).equals(storeAsserions.get(k+1))) {
                       System.out.println("Do something else");
                   }
                }
            }
        }
//这是存储在ArrayList中的.xlsx文件

对于(inti=1;i一个可能的解决方案是使用数据库,如果给定适当的索引,它可以非常快地进行搜索。假设数据适合内存,则可以更快

原则 对于像这样的问题

for (X x : xList) {
    for (Y y : yList) {
        if (x.someAttr() == y.someAttr()) doSomething(x, y);
    }
}
您只需根据如下属性将一个列表划分为多个存储桶

Map<A, List<Y>> yBuckets = new HashMap<>();
yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
    (v==null ? new ArrayList<>() : v).add(y));
现在,我们需要在bucket上进行一些循环,这样至少有一个
equals
测试总是正确的,这样我们就不用处理不匹配的数据了

x.noun1.equals(z.noun1) && y.noun2.equals(z.noun2)
我建议像这样的循环

for (Pair z : sList) {
    for (Triplet x : smallListOfTripletsHavingNoun1SameAsZ) {
        for (Triplet y : smallListOfTripletsHavingNoun2SameAsZ) {
            doSomething();
        }
    }
}
小列表得到第一节中的计算结果

不会比较任何不匹配的条目,因此复杂性会从立方减少到匹配的数量(=如果要打印代码行的数量)

附录-
yBuckets
让我们假设
xList
看起来像

[
  {id: 1, someAttr: "a"},
  {id: 2, someAttr: "a"},
  {id: 3, someAttr: "b"},
]
然后
yBuckets
应该是

{
  "a": [
    {id: 1, someAttr: "a"},
    {id: 2, someAttr: "a"},
  ],
  :b": [
    {id: 3, someAttr: "b"},
  ],
}
一个简单的方法是,如何创建这样一个地图

yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
   (v==null ? new ArrayList<>() : v).add(y));
yList.forEach(y->yBuckets.compute(y.someAttr(),(k,v)->
(v==null?新建ArrayList():v).add(y));
明文:

  • 对于
    yList
    中的每个
    y
  • (k,v)
    的形式获取相应的地图条目
  • v
    为空时,创建一个新列表
  • 否则,请使用列表
    v
  • 在任何情况下,将
    y
    添加到它
  • 并将其存储回映射(除非在第三步中创建了新列表,否则这是一个无操作)

    • 一种可能的解决方案是使用数据库,如果有适当的索引,它可以非常快速地进行搜索。如果数据适合内存,则可以更快

      原则 对于像这样的问题

      for (X x : xList) {
          for (Y y : yList) {
              if (x.someAttr() == y.someAttr()) doSomething(x, y);
          }
      }
      
      您只需根据如下属性将一个列表划分为多个存储桶

      Map<A, List<Y>> yBuckets = new HashMap<>();
      yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
          (v==null ? new ArrayList<>() : v).add(y));
      
      现在,我们需要在bucket上进行一些循环,这样至少有一个
      equals
      测试总是正确的,这样我们就不用处理不匹配的数据了

      x.noun1.equals(z.noun1) && y.noun2.equals(z.noun2)
      
      我建议像这样的循环

      for (Pair z : sList) {
          for (Triplet x : smallListOfTripletsHavingNoun1SameAsZ) {
              for (Triplet y : smallListOfTripletsHavingNoun2SameAsZ) {
                  doSomething();
              }
          }
      }
      
      小列表得到第一节中的计算结果

      不会比较任何不匹配的条目,因此复杂性会从立方减少到匹配的数量(=如果要打印代码行的数量)

      附录-
      yBuckets
      让我们假设
      xList
      看起来像

      [
        {id: 1, someAttr: "a"},
        {id: 2, someAttr: "a"},
        {id: 3, someAttr: "b"},
      ]
      
      然后
      yBuckets
      应该是

      {
        "a": [
          {id: 1, someAttr: "a"},
          {id: 2, someAttr: "a"},
        ],
        :b": [
          {id: 3, someAttr: "b"},
        ],
      }
      
      一个简单的方法是,如何创建这样一个地图

      yList.forEach(y -> yBuckets.compute(y.someAttr(), (k, v) ->
         (v==null ? new ArrayList<>() : v).add(y));
      
      yList.forEach(y->yBuckets.compute(y.someAttr(),(k,v)->
      (v==null?新建ArrayList():v).add(y));
      
      明文:

      • 对于
        yList
        中的每个
        y
      • (k,v)
        的形式获取相应的地图条目
      • v
        为空时,创建一个新列表
      • 否则,请使用列表
        v
      • 在任何情况下,将
        y
        添加到它
      • 并将其存储回映射(除非在第三步中创建了新列表,否则这是一个无操作)

      你在
      1
      开始循环并跳过索引
      0
      处的第一个元素的任何原因?你的朋友建议的哈希表是正确的。将
      storeAsserions
      列表更改为
      映射,其中键是列表中的值,整数是在列表中找到该值的索引列表。@Andreas我已经更新了问题。基本上,两个ArrayList中的所有内容都是动词:名词:名词对,我不关心用于搜索的动词,但我想将它们保留在ArrayList中以供输出。另外,动词[0]、名词[1]、名词[2]……都不是存储在一个索引中。get(I)等。代价高昂?我不这么认为(不是100%确定)。它实际上只是从ArrayList中获取索引。问题是有太多不同的迭代需要运行。通常我的较小ArrayList有300行长,因此需要75000000000(750000000)使用我正在使用的方法的操作从
      1
      开始循环,并跳过第一个元素,即索引
      0
      ?您的朋友建议的哈希表是正确的。将
      storeAsserions
      列表更改为
      映射,其中键是列表中的值,整数是索引在列表中找到该值的位置。@Andreas我已经更新了问题。基本上,两个ArrayList中的所有内容都是动词:名词:名词对,我不关心用于搜索的动词,但我想将它们保留在ArrayList中以供输出。此外,动词[0]、名词[1]、名词[2]…所有内容都不存储在一个索引中。get(I)等等。成本高吗?我不这么认为(不是100%确定)。这实际上只是从ArrayList获取一个索引。问题是有太多不同的迭代需要运行。通常我的较小的ArrayList有300行长,因此需要75000000000(7500亿)使用我正在使用的方法,我想我了解所有的事情,除了你说Map@JohnMeehan整个神奇之处就在于
      Map::compute
      ,请参见我的附录。有关分区应该是什么样子的,请参见这里的示例。谢谢,我想我了解所有内容,除了您所说的“Map@JohnMeehan整个神奇之处在于
      Map::compute
      ,请参阅我的附录