大型同义词集中的 WordNetSimalarity
Posted
技术标签:
【中文标题】大型同义词集中的 WordNetSimalarity【英文标题】:WordNetSimalarity in large dataset of synsets 【发布时间】:2013-05-04 22:12:08 【问题描述】:我使用 wordnet 相似性 java api 来测量两个同义词集之间的相似性:
public class WordNetSimalarity
private static ILexicalDatabase db = new NictWordNet();
private static RelatednessCalculator[] rcs =
new HirstStOnge(db), new LeacockChodorow(db), new Lesk(db), new WuPalmer(db),
new Resnik(db), new JiangConrath(db), new Lin(db), new Path(db)
;
public static double computeSimilarity( String word1, String word2 )
WS4JConfiguration.getInstance().setMFS(true);
double s=0;
for ( RelatednessCalculator rc : rcs )
s = rc.calcRelatednessOfWords(word1, word2);
// System.out.println( rc.getClass().getName()+"\t"+s );
return s;
主类
public static void main(String[] args)
long t0 = System.currentTimeMillis();
File source = new File ("TagsFiltered.txt");
File target = new File ("fich4.txt");
ArrayList<String> sList= new ArrayList<>();
try
if (!target.exists()) target.createNewFile();
Scanner scanner = new Scanner(source);
PrintStream psStream= new PrintStream(target);
while (scanner.hasNext())
sList.add(scanner.nextLine());
for (int i = 0; i < sList.size(); i++)
for (int j = i+1; j < sList.size(); j++)
psStream.println(sList.get(i)+" "+sList.get(j)+" "+WordNetSimalarity.computeSimilarity(sList.get(i), sList.get(j)));
psStream.close();
catch (Exception e) e.printStackTrace();
long t1 = System.currentTimeMillis();
System.out.println( "Done in "+(t1-t0)+" msec." );
我的数据库包含 595 个同义词集,这意味着方法 computeSimilarity
将被调用 (595*594/2) 时间
要计算两个词之间的相似度,它的花费超过5000 ms
!
所以要完成我的任务,我至少需要一周时间!!
我的问题是如何减少这段时间!
如何提高性能??
【问题讨论】:
【参考方案1】:在线程/分叉方面,Perl 与许多其他语言不同。
使 Perl 线程与其他线程不同的关键之一是默认情况下不共享数据。这使线程更容易和更安全地使用,您不必担心库或大多数代码的线程安全,只需担心线程位。然而,由于 Perl 必须将解释器的副本和所有已加载的模块放入每个线程,这可能会导致性能下降和内存消耗。
说到分叉,我只会谈论 Unix。 Perl 使用线程在 Windows 上模拟 fork,它可以工作,但它可能很慢且有问题。
分叉优势
创建分叉非常快 非常健壮分叉的缺点
进程之间的通信可能会很慢而且很尴尬线程优势
线程协调和数据交换相当容易 线程相当容易使用线程缺点
每个线程都占用大量内存 线程启动速度可能很慢 线程可能有问题(perl 越新越好) 数据库连接不跨线程共享一般来说,要从 Perl 线程中获得良好的性能,最好启动一个线程池并重用它们。可以更轻松地创建、使用和丢弃分叉。
对于任何一种情况,您都可能需要一些东西来管理您的员工池。对于分叉,您将要使用 Parallel::ForkManager 或 Child。 Child 特别好用,因为它内置了进程间通信。
对于线程,您将要使用threads::shared、Thread::Queue 并读取perlthrtut。 此外,线程数将取决于您的计算机拥有的内核数。如果您有四个内核,那么创建 3 个以上的线程并不是很有帮助(主程序为 3 + 1)。
说实话,线程/分叉可能不是要走的路。事实上,在许多情况下,它们甚至会因为开销而减慢速度。如果你真的需要速度,最好的方法是通过分布式计算。我建议您研究某种分布式计算平台,以使您的运行时更好。如果您可以将 search/compareTo 空间的维度减少到小于 n^2,那么 map reduce 或 Hadoop 可能是一个不错的选择;否则,您只会有大量开销,并且无法使用 Hadoop 提供的真正可扩展性 (@Thomas Jungblut)。
【讨论】:
Hadoop 最不适合计算相似度矩阵。 为什么?有哪些替代方案?我之所以建议它,是因为我在没有使用分布式计算的情况下做过类似的工作,并且对结果非常不满意。 那么您实际上从未为此使用过 Hadoop。您不能使用 mapreduce 有效地表达 O(n^2) 算法(通常是相似度矩阵的计算)。最后,您只会有大量开销,并且无法使用 Hadoop 提供的真正可扩展性。替代品是例如使用 minhashing 查找可以在 O(n * k) 中比较的少量强相关项目,而不是整个项目序列。如果你有一把锤子,并不是所有东西都应该像钉子。 你误读了我的评论;我从未使用过 Hadoop……我的观点是线程/分叉不会解决 OP 的问题(实际上会使情况变得更糟)。相反,他需要通过分布式计算找到某种方式来使他的运行时间更好(当然减少采样空间会使其更快)。 如果你从来没有用过它,那么干脆不推荐它,因为它会让他的问题变得更糟。【参考方案2】:我不知道是否可以优化这个算法。
但你绝对可以跑得更快。在我的机器上,这个操作花费的时间减少了两倍,所以如果你有 8 个 i7 内核,你需要 15 个小时来处理所有事情(如果你并行处理循环)
您可以在 Amazon Web Services 获得虚拟机。因此,如果您拥有多台机器并在每台机器上对不同的数据块运行多线程处理 - 您将在几个小时内完成。
技术上可以使用 Hadoop,但如果您只需要运行一次 - 我认为并行计算并在多台机器上启动会更简单。
【讨论】:
【参考方案3】:你试过MatrixCalculator吗?
【讨论】:
【参考方案4】:我认为语言不是您的问题。
您可以帮助自己处理并行性。我认为这将是 map reduce 和 Hadoop 的一个很好的候选。
【讨论】:
并行结果比顺序结果差。任何其他建议以上是关于大型同义词集中的 WordNetSimalarity的主要内容,如果未能解决你的问题,请参考以下文章