Java 大型数据集的优化搜索技术
我目前正在做一个项目,我需要处理一个大约300万行长的.csv文件和不同的.xlsx文件,这些文件的大小介于10行到1000行之间。我试图在.xlsx文件和.csv文件中找到不同单元格之间的共性。 这样做。我已读入.csv文件和.xslx文件,并将其存储在ArrayList中。 我有我想要的工作,但是我使用的方法是O(n^3),在每个循环之间使用3嵌套的for循环do搜索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;
//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
,请参阅我的附录