提高文本处理的性能

时间:2015-03-20 15:17:08

标签: javascript performance text process

我编写了一个程序,指示文本中所需单词类的所有实例。我就是这样做的:

  • 从整个文本中提取一系列单词

  • 迭代此数组。对于每个单词,看看它的第一个字母是什么。

    • 跳转到所选单词类所有单词的对象中的相应数组(例如' S')并迭代它。如果找到该单词则中断并将其推入匹配数组中。
  • 检查完所有单词后,迭代匹配数组并突出显示文本中的每一个。

一个由240000个单词组成的文本在100秒内处理有关名词的事宜,约4.5秒处理关于我的机器上的介词。

我正在寻找提高绩效的方法,这些是我能提出的想法:

  • 重新排列我的词汇表的每个块中的项目。对它们进行排序,如果单词以人声开头,所有将辅音作为第二个字符的项目首先出现,反之亦然。 (假设双声或辅音的词很少见)
  • 将文本结构化为章节,仅处理当前显示的章节。

那些坚实的想法是否有更多的想法或经过验证的技术来改进这种处理?

6 个答案:

答案 0 :(得分:9)

使用javascript的强大功能。

它使用字符串键作为基本操作来操作字典。对于每个单词类,构建一个对象,每个可能的单词是一个键,一些简单的值如true或1.然后检查每个单词只是typeof(wordClass[word]) !== "undefined"。我希望这会快得多。

正则表达式是Javascript的另一个高度优化的区域。您可以将整个事物作为每个单词类的一个大型正则表达式来完成。如果您的突出显示是HTML格式,那么您也可以在RE上使用替换来获得结果。这项工作可能取决于你的单词集的大小。

答案 1 :(得分:5)

我建议的解决方案是实现trie数据结构。实现需要更多的努力,但与哈希表(字典)相比有几个优点。

在trie中查找数据最多需要O( k )时间,其中<​​em> k 是搜索字符串的长度。使用哈希表,将每个单词存储为键可能有效,但是您将哪些值存储为表中该键的值?对于这个问题,哈希表似乎对我来说效率不高。

此外,trie可以通过预订遍历提供您的密钥条目的字母顺序。哈希表不能。要对其键进行排序,您必须自己实现排序功能,这只会增加时间和空间。

如果您进一步阅读尝试,则会遇到suffix treesradix trees,它们会解决您尝试解决的确切问题。因此,从某种意义上说,你正在重新发明轮子,但我并不是说这是一件坏事。学习这些东西会让你成为更好的程序员。

我们可以将一个简单的trie实现为一组存储三条信息的连接节点:1)符号(字符),2)指向该节点的第一个子节点的指针,以及3)指向父节点的指针节点的下一个孩子。

class TrieNode {
  constructor(symbol) {
    this.symbol = symbol;
    this.child = null;
    this.next = null;
  }
}

然后,您可以构建一个单词网络,通过单词中的每个字母链接在一起。共享相同前缀的单词通过子指针和下一个指针本地链接在一起,因此查找非常快。我鼓励你进一步研究尝试。它们是整洁的数据结构,我认为它最适合您的问题。

答案 2 :(得分:4)

我认为耗费高计算时间的步骤将是:

  • 搜索世界级容器中的特定单词。
  • 突出显示源文档上的匹配项。

因此,我建议使用更高效的数据结构来存储 word类容器匹配列表。因此搜索和查找运行得更快。

如果我理解您的问题,只想突出显示世界级列表中的单词。所以我建议 Bloom Filter 非常出色地完成这项工作。

http://en.wikipedia.org/wiki/Bloom_filter

布隆过滤器是一个集合容器,您可以存储任何元素(单词)并检查此集合中是否已有任何新单词。速度非常快,适合大数据处理。

用例将是:

  • 您将单词类存储在Bloom过滤器中,我们将其命名为 bfWordClass
  • 遍历提取的单词列表,检查每个单词是否为 bfWordClass 的成员(此操作非常快且100%准确)。
  • 如果单词确实属于 bfWordClass ,则您查找文本并突出显示它们。您可以考虑使用另一种数据结构来存储从文档中提取的唯一单词以及文档中找到的所有索引,以便更快地参考。

答案 3 :(得分:2)

  • 使用前3个字符作为键,而不是第一个字符。
  • 将您的工作卸载到许多background threads
  • 首先处理可见文字

答案 4 :(得分:2)

2,40,000个单词确实是客户端处理的大数据,当您突出显示文本时,这将在javascript和DOM操作中产生性能问题。如果可能,您应尝试处理较小的集合,如页面或段落或部分。

如果您能够或不能减少有效的单词集,那么您可以尝试进行文本处理的一些优化:

在DOM中存储文本

您可以尝试两种方法:

  1. 包含所有文本的单个DOM元素,即240k字
  2. 多个DOM元素,每个元素包含N个单词,比如240个元素,每个元素包含1000个单词。
  3. 你必须使用像jsPerf这样的工具,看看innerHTML在两种方法中的变化有多快,即在单个DOM元素中替换大的innerHTML或文本,而不是替换匹配的DOM元素的多个innerHTML。

    匹配 - 完全输入后突出显示的字词

    例如,您希望在文本完全输入后突出显示“Javascript”和“text”。在这种情况下,正如@DrC所提到的,预处理文本以存储密钥与数据是一件好事。 为单词生成一个键(如果你想匹配不区分大小写,或者忽略特殊字符等,你可能想要标准化键,即'nosql'将是'NoSQL'或'NOSQL'或'No-SQL的关键`。 您的查找对象将如下所示:

    {
      'nosql': {'matches':[{'NoSQL':3},{'NOSQL':6}],  // indexes of strings where this occurs
    
    }
    

    每当搜索到某个单词时,您都会生成用于查找所有匹配项索引的键,并突出显示该文本。

    匹配 - 在键入字词时突出显示 对于这种方法,您需要在javascript对象中创建基于trie的结构。 另一种方法是基于生成和编译正则表达式 当前键入的字符串,如果用户具有正则表达式的类型'jav' \jav\gi并对整个文本进行正则表达式匹配。 两种方法都需要进行性能比较

答案 5 :(得分:-3)

我会做这样的事情。

HTML

<section id="text">All keywords in this sentence will be marked</section>

的JavaScript

element = document.getElementId('text');
text = element.innerHTML;
array_of_keywords = ['keyword', 'will'];
eval('text = text.replace(/(' + array_of_keywords.join('|') + ')/g, "<mark>\$1</mark>");');
element.innerHTML = text;