快速将文本拆分成句子(Java)

时间:2014-04-07 07:21:10

标签: java performance nlp opennlp sentence

我有一套文章描述,我必须将文本分成句子。第一个实现使用opennlp工具sentdetect,它工作得非常好,但对我来说太慢了。 是否有类似的东西表现得更快,并且质量相似或略差的结果?

注意:我正在处理(大量的)简短的德语文本。

5 个答案:

答案 0 :(得分:7)

是的,这有助于提及你正在与德语合作:)

可以在GATE中找到带有缩写列表的基于正则表达式的句子检测器。它使用位于here的三个文件。正则表达式非常简单:

//more than 2 new lines
(?:[\u00A0\u2007\u202F\p{javaWhitespace}&&[^\n\r]])*(\n\r|\r\n|\n|\r)(?:(?:[\u00A0\u2007\u202F\p{javaWhitespace}&&[^\n\r]])*\1)+

//between 1 and 3 full stops
\.{1,3}"?

//up to 4 ! or ? in sequence
(!|\?){1,4}"?

可以找到使用这3个文件的代码here

我会使用可在网络上找到的内容来增强正则表达式,例如this one

然后我会想到GATE列表中所有单词的德语翻译。如果这还不够,我会浏览一些缩写列表:12,并自行创建列表。

编辑:

如果性能如此重要,我不会将整个GATE用于句子分割器 - 切换到文档,创建注释,然后再解析它们需要时间和内存等。

我认为最好的方法是从RegexSentenceSplitter类(link above)获取代码并根据您的上下文进行调整。

我认为代码太长而无法在此处粘贴。你应该看到execute()方法。通常,它会查找内部,外部和阻塞正则表达式的所有匹配项,然后迭代并仅使用那些不与任何阻塞重叠的内部和外部匹配。

以下是您应该查看/重用的一些片段:

  • 如何解析文件

    // for each line
    if(patternString.length() > 0) patternString.append("|");
    patternString.append("(?:" + line + ")");
    
    //...
    return Pattern.compile(patternString.toString());
    
  • 在execute方法中,如何填充阻塞分割:

    Matcher nonSplitMatcher = nonSplitsPattern.matcher(docText);
    //store all non split locations in a list of pairs
    List<int[]> nonSplits = new LinkedList<int[]>();
    while(nonSplitMatcher.find()){
       nonSplits.add(new int[]{nonSplitMatcher.start(), nonSplitMatcher.end()});
    }
    

同时检查否决方法“检查可能的匹配是否被非分割匹配否决。如果与否决区域有任何重叠,则可能的匹配被否决。”

希望这有帮助。

答案 1 :(得分:2)

也许String.split("\\. |\\? |! ");可以吗?

答案 2 :(得分:2)

总的来说,我认为OpenNLP比基于规则的分段器(如Stanford分段器)或实现正则表达式来解决任务更好(性能方面)。基于规则的分段器必然会遗漏一些例外情况。例如,德语句子“Ich wurde am 17. Dezember geboren”(我出生于12月17日)将被错误地分成17个句子后的许多基于规则的分段符号,特别是如果它们被构建英语规则,而不是德语。即使您的文本质量非常好,因为它们构成语法正确的德语,这样的句子也会出现。因此,非常重要的是要检查您想要使用的分段器的语言模型。

PS:在OpenNLP,BreakIterator分段器和Stanford分段器中,OpenNLP最适合我。

答案 3 :(得分:1)

值得一提的是,Java标准API库为detecting test boundaries提供了与语言环境相关的功能。 BreakIterator可用于确定句子边界。

答案 4 :(得分:0)

还有一个解决方案。不知道与您的解决方案相比性能如何,但肯定是最全面的。您可以使用ICU4J库和srx文件。你可以在这里下载的图书馆http://site.icu-project.org/download/52#TOC-ICU4J-Download。就像它的多语言魅力一样。

package srx;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import net.sf.okapi.common.ISegmenter;
import net.sf.okapi.common.LocaleId;
import net.sf.okapi.common.Range;
import net.sf.okapi.lib.segmentation.LanguageMap;
import net.sf.okapi.lib.segmentation.Rule;
import net.sf.okapi.lib.segmentation.SRXDocument;

public class Main {

/**
 * @param args
 */
public static void main(String[] args) {

    if(args.length != 2) return;

    SRXDocument doc = new SRXDocument();

    String srxRulesFilePath = args[0];
    String text = args[1];
    doc.loadRules(srxRulesFilePath);
    LinkedHashMap<String, ArrayList<Rule>> rules =  doc.getAllLanguageRules();
    ArrayList<LanguageMap> languages = doc.getAllLanguagesMaps();
    ArrayList<Rule> plRules = doc.getLanguageRules(languages.get(0).getRuleName());     
    LocaleId locale = LocaleId.fromString("pl_PL");     
    ISegmenter segmenter = doc.compileLanguageRules(LocaleId.fromString("pl_PL"), null);


    segmenter.computeSegments(text);

    List<Range> ranges = segmenter.getRanges();

    System.out.println(ranges.size());
    for (Range range : ranges) {
        System.out.println(range.start);
        System.out.println(range.end);
    }
}

}