繁体   English   中英

如何加快Java文本文件解析器的速度?

[英]How can I speed up my Java text file parser?

我正在阅读大约600个文本文件,然后分别解析每个文件,并将所有术语添加到地图中,以便我可以知道600个文件中每个单词的频率。 (大约400MB)。

我的解析器功能包括以下步骤(有序):

  • 在两个标签之间查找文本,这是每个文件中要读取的相关文本。
  • 小写所有文字
  • 具有多个分隔符的string.split。
  • 用这样的词创建一个arrayList:“ aaa-aa”,然后添加到上面拆分的字符串中,并将“ aaa”和“ aa”折扣为String []。 (我这样做是因为我希望“-”成为分隔符,但我也希望“ aaa-aa”仅是一个单词,而不是“ aaa”和“ aa”。
  • 获取String []并映射到Map = new HashMap ...(单词,频率)
  • 打印所有内容。

在双核2.2GHz,2GB Ram上,我花了大约8分钟48秒。 我想提出有关如何加快此过程的建议。 我应该期望它这么慢吗? 如果可能的话,我怎么能(在netbeans中)知道哪些函数需要花费更多的时间来执行?

找到的独特词:398752。

码:

File file = new File(dir);
String[] files = file.list();

for (int i = 0; i < files.length; i++) {
    BufferedReader br = new BufferedReader(
        new InputStreamReader(
            new BufferedInputStream(
                new FileInputStream(dir + files[i])), encoding));
    try {
        String line;
        while ((line = br.readLine()) != null) {
            parsedString = parseString(line); // parse the string
            m = stringToMap(parsedString, m);
        }
    } finally {
        br.close();
    }
}

编辑:检查:

![在此处输入图片描述] [1]

我不知道得出什么结论。


编辑:80%的时间使用此功能

    public String [] parseString(String sentence){
         // separators; ,:;'"\/<>()[]*~^ºª+&%$ etc..
        String[] parts = sentence.toLowerCase().split("[,\\s\\-:\\?\\!\\«\\»\\'\\´\\`\\\"\\.\\\\\\/()<>*º;+&ª%\\[\\]~^]");

        Map<String, String> o = new HashMap<String, String>(); // save the hyphened words, aaa-bbb like Map<aaa,bbb>

        Pattern pattern = Pattern.compile("(?<![A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû-])[A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû]+-[A-Za-zÁÉÍÓÚÀÃÂÊÎÔÛáéíóúàãâêîôû]+(?![A-Za-z-])");
        Matcher matcher = pattern.matcher(sentence);

    // Find all matches like this: ("aaa-bb or bbb-cc") and put it to map to later add this words to the original map and discount the single words "aaa-aa" like "aaa" and "aa"
        for(int i=0; matcher.find(); i++){
           String [] tempo = matcher.group().split("-");
           o.put(tempo[0], tempo[1]);
        }
        //System.out.println("words: " + o);


        ArrayList temp = new ArrayList();
        temp.addAll(Arrays.asList(parts));

        for (Map.Entry<String, String> entry : o.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            temp.add(key+"-"+value);
            if(temp.indexOf(key)!=-1){
                temp.remove(temp.indexOf(key));
            }
            if(temp.indexOf(value)!=-1){
                temp.remove(temp.indexOf(value));
            }
        }


        String []strArray = new String[temp.size()];
        temp.toArray(strArray);
                return strArray;

  }

600个文件,每个文件约0.5MB

EDIT3#-不再在每次读取一行时编译该模式。 新图像为:

在此处输入图片说明

2 在此处输入图片说明

如果尚未使用-Xmx,请确保增加堆大小。 对于此应用程序,影响可能是惊人的。

您的代码中可能对性能产生最大影响的部分是执行最多的部分-您未显示的部分。

内存截图后更新

查看屏幕快照中的所有Pattern $ 6对象。 我认为您正在重新编译很多模式-可能是每一行。 这将花费很多时间。

更新2-将代码添加到问题之后。

是的-每行编译两种模式-显式模式,以及拆分中的“-”(当然便宜得多)。 我希望他们不要将split()添加到String,除非它以编译模式作为参数。 我看到其他一些可以改进的地方,但是没有什么比大编译好。 只需在此函数之外将模式编译一次,也许作为静态类成员即可。

如果尚未执行此操作,请使用BufferedInputStream和BufferedReader读取文件。 这样的双缓冲比单独使用BufferedInputStream或BufferedReader更好。 例如:

BufferedReader rdr = new BufferedReader(
    new InputStreamReader(
        new BufferedInputStream(
            new FileInputStream(aFile)
        )
        /* add an encoding arg here (e.g., ', "UTF-8"') if appropriate */
    )
);

如果您发布了代码的相关部分,那么我们就有机会评论如何改进处理过程。

编辑:

根据您的修改,这里有一些建议:

  1. 编译一次模式并将其保存为静态变量,而不是每次调用parseString都进行编译。
  2. 第一次调用它们时,请存储temp.indexOf(key)temp.indexOf(value) ,然后使用存储的值而不是第二次调用indexOf

尝试使用单个正则表达式,该正则表达式具有与标签中每个单词匹配的组-因此,单个正则表达式可用于您的整个输入,并且不会有单独的“拆分”阶段。

否则,您的方法似乎是合理的,尽管我不明白“获取String [] ...”的含义-我认为您正在使用ArrayList。 无论如何,都应尽量减少对象的创建,无论是建造成本还是垃圾收集成本。

只是解析花费了这么长时间,还是正在读取文件?

对于文件读取,您可以通过在多个线程上读取文件来加快速度。 但是第一步是要弄清楚是花时间还是在进行解析,因此您可以解决正确的问题。

通过Netbeans探查器运行代码,找出最耗时的时间(在项目上单击鼠标右键并选择探查,请确保您没有浪费时间)。

您向我们展示的代码中没有任何东西显然是性能问题的根源。 问题可能与您解析线条或提取单词并将其放入地图的方式有关。 如果您需要更多建议,则需要发布这些方法的代码,以及声明/初始化地图的代码。

我的一般建议是分析应用程序并查看瓶颈所在,然后使用该信息找出需要优化的内容。

@Ed Staub的建议也很合理。 使用太小的堆运行应用程序导致严重的性能问题。

看起来大部分时间都花在正则表达式上。 我将首先尝试在不使用正则表达式的情况下编写代码,然后使用多个线程,好像该进程似乎仍受CPU约束。

对于计数器,我将考虑使用TObjectIntHashMap来减少计数器的开销。 我将只使用一个映射,而不是创建字符串数组-然后使用计数来构建另一个映射,这可能会浪费大量时间。

预编译模式,而不是每次都通过该方法进行编译,并摆脱双重缓冲:使用new BufferedReader(new FileReader(...))。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM