Algorithm 优化O(n^2)算法所需的建议
我期待着优化一个相当简单的算法,目前正在进行 O(n2)。我有一个档案,每个档案都需要 可以与同一文件中的其他文件进行比较。如果这两个是相同的 “相同”(比较器函数相当复杂),匹配 记录被输出。请注意,可能有多条记录匹配 彼此之间,没有秩序感——只有在匹配是真是假的情况下 伪代码:Algorithm 优化O(n^2)算法所需的建议,algorithm,optimization,hadoop,Algorithm,Optimization,Hadoop,我期待着优化一个相当简单的算法,目前正在进行 O(n2)。我有一个档案,每个档案都需要 可以与同一文件中的其他文件进行比较。如果这两个是相同的 “相同”(比较器函数相当复杂),匹配 记录被输出。请注意,可能有多条记录匹配 彼此之间,没有秩序感——只有在匹配是真是假的情况下 伪代码: For (outRec in sourceFile) { Get new filePointer for targetFile //starting from the top of the file for i
For (outRec in sourceFile) {
Get new filePointer for targetFile //starting from the top of the file for inner loop
For (inRec in targetFile) {
if (compare(outRec, inRec) == TRUE ) {
write outRec
write inRec
}
increment some counters
}
increment some other counters
}
数据没有以任何方式排序,也没有预处理
可以对数据进行排序
有没有关于这件事怎么会变得不那么重要的想法
O(n2)?我正在考虑应用MapReduce范例
在代码上,分解外部和内部循环,可能使用
链式映射函数。我很确定我已经把密码弄明白了
Hadoop,但我想在花时间编写代码之前检查替代方案
它
感谢您的建议
添加:记录类型。基本上,我需要匹配名称/字符串。这个
下面的示例中显示了匹配的类型
1,Joe Smith,Daniel Foster
2,Nate Johnson,Drew Logan
3,Nate Johnson, Jack Crank
4,Joey Smyth,Daniel Jack Foster
5,Joe Morgan Smith,Daniel Foster
Expected output:
Records 1,4,5 form a match set
End of output
1、乔·史密斯、丹尼尔·福斯特
内特·约翰逊,德鲁·洛根
3,内特·约翰逊,杰克·克兰克
乔伊·史密斯,丹尼尔·杰克·福斯特
5、乔·摩根·史密斯、丹尼尔·福斯特
预期产出:
记录1、4、5构成一个匹配集
输出结束
补充:这些文件将相当大。最大的文件是
预计将有大约2亿条记录。假设文件的大小不会太大,我会遍历整个文件,计算行的散列,并跟踪散列/行(或文件指针位置)的组合。然后对哈希列表进行排序,并识别那些多次出现的哈希 只需浏览文件的每条记录并将它们插入到哈希表中即可。在每个步骤中,检查记录是否已经在哈希表中。如果是,则输出它。这可以在O(n)中完成。我们需要了解有关比较函数的更多信息。你的比较是传递性的吗?(也就是说,A==B和B==C是否意味着A==C?)?(A==B是否意味着B==A?) 如果您的比较函数是传递的和自反的,并且许多记录相等是常见的,那么您可以通过将记录与组中的一个“代表性样本”进行比较,将其分组。在最好的情况下,这可能接近O(N)
请注意,对记录进行哈希运算时,假定哈希(A)=哈希(B)比较(A,B)=真,但如果比较(A,B),则即使在字节(A)!=字节(B)设计适当的散列算法可能很棘手。我不确定比较器和数据集的属性,但假设比较器在行上定义了等价关系,这里什么也没有:
请注意,在最坏的情况下,根据您的问题描述,您无法获得比O(n^2)更好的结果,这仅仅是因为您必须输出的匹配记录可能有O(n^2)个结果 FYI MapReduce将而不是改善解决方案的算法复杂性。它增加了一些开销,但随后将其并行化,以便您可以在更少的挂钟时间内使用必要的资源 为了提高你的挂钟时间,首先要做的是找到避免进行比较的方法。任何这样做的方式都将是一场胜利。即使您的比较逻辑很复杂,您仍然可以使用排序来提供帮助 例如,假设您有一些维度,这些数据分布在其中。在该维度中差异过大的数据保证不会比较相等,尽管在该维度中接近并不能保证相等。然后,您可以按该维度对数据进行排序,然后只在该维度中相近的元素之间运行比较。瞧!大多数
O(n*n)
比较现在都不存在了
让我们把它弄得更复杂些。假设您可以识别两个相互独立的维度。按照第一个维度对数据进行排序。将第一个维度中的数据划分为条带。(使条带重叠的最大值在该尺寸上有所不同,并且比较时仍然相等。)现在取下每个条带,并按第二个尺寸对其进行排序。然后在该维度中可以接受的相近元素对之间进行比较,如果该元素对比较相等,则将其包含在答案中,这是该元素对可能出现的第一个条带。(这种重复数据消除逻辑是必需的,因为重叠可能意味着比较相等的一对可以出现在多个条带中。)这可能比第一种方法更好,因为您已经设法缩小了范围,以便只将行与少量“附近”行进行比较
如果你想使用更少的资源,你需要专注于避免实际进行个别比较的方法。你在这条道路上的任何想法都会有所帮助。正如你已经提到的,你不会有比O(n^2)更好的运气,但你可以将其平行化 我有一个可以使用HDFS的工作解决方案,您可以使用分布式缓存来扩展它
public class MatchImporter extends Mapper<LongWritable, Text, Text, Text> {
FileSystem fs;
private BufferedReader stream;
@Override
protected void setup(Context context) throws IOException,
InterruptedException {
fs = FileSystem.get(context.getConfiguration());
}
private void resetFile() throws IOException {
if (stream != null)
stream.close();
stream = new BufferedReader(new InputStreamReader(fs.open(new Path(
"files/imp/in/target.txt"))));
}
private boolean compare(Text in, String target) {
return target.contains(in.toString());
}
enum Counter {
PROGRESS
}
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
resetFile();
String line = null;
while ((line = stream.readLine()) != null) {
// increment a counter to don't let the task die
context.getCounter(Counter.PROGRESS).increment(1);
context.progress();
if (compare(value, line)) {
context.write(new Text(line), value);
}
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = new Job(conf);
job.setMapperClass(MatchImporter.class);
job.setReducerClass(Reducer.class);
job.setJarByClass(MatchImporter.class);
Path in = new Path("files/imp/in/source.txt");
Path out = new Path("files/imp/out/");
FileInputFormat.addInputPath(job, in);
FileSystem fs = FileSystem.get(conf);
if (fs.exists(out))
fs.delete(out, true);
SequenceFileOutputFormat.setOutputPath(job, out);
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.waitForCompletion(true);
}
}
和target.txt
john meat
jay hardly
将导致减速器输出:
john meat john
诀窍在于,您可以拆分source.txt并并行地进行比较。这将给你加速,但不会让你更好地在大O
这里有一个重要提示:
您必须使用cou报告进度
john meat john