Частота слова каждого слова в текстовом файле 2 ГБ в кодировке UTF-8 на Java - PullRequest
0 голосов
/ 01 марта 2019

Я работаю над проектом, и там мне нужно выяснить частоту каждого слова в большом корпусе из более чем 100 миллионов бенгальских слов.Размер файла составляет около 2 ГБ.Мне на самом деле нужны самые частые 20 слов и наименее частые 20 слов с подсчетом частоты.Я сделал тот же код в PHP, но это занимает так много времени (код все еще работает через неделю).Таким образом, я пытаюсь сделать это на Java.

В этом коде он должен работать следующим образом:

- читать строку из корпуса nahidd_filtered.txt

- разделять пробелами

  • для каждого разбитого слова, читать весь файл частоты freq3.txt

    • , если слово найдено, увеличить счетчик частоты и сохранитьв этом файле

    • else count = 1 (новое слово) и сохранить количество частот в этом файле

У меня естьпопытался прочитать фрагмент текста из nahidd_filtered.txt корпус, используя цикл, и слово с частотой сохраняется в freq3.txt .В файле freq3.txt хранится подсчет частоты, например,

Word1 Frequncy1 (один пробел между ними)

Word2 Frequency2

...........

Проще говоря, мне нужны топ-20 наиболее часто встречающихся и 20 наименее часто встречающихся слов вместе с их частотным отсчетом из большого файла корпуса в кодировке UTF-8.Пожалуйста, проверьте код и предложите мне, почему это не работает, или любые другие предложения.Большое спасибо.

import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class Main {


private static String fileToString(String filename) throws IOException {
    FileInputStream inputStream = null;
    Scanner reader = null;
    inputStream = new FileInputStream(filename);
    reader = new Scanner(inputStream, "UTF-8");

    /*BufferedReader reader = new BufferedReader(new FileReader(filename));*/
    StringBuilder builder = new StringBuilder();


    // For every line in the file, append it to the string builder
    while (reader.hasNextLine()) {
        String line = reader.nextLine();
        builder.append(line);
    }

    reader.close();
    return builder.toString();
}

public static final String UTF8_BOM = "\uFEFF";

private static String removeUTF8BOM(String s) {
    if (s.startsWith(UTF8_BOM)) {
        s = s.substring(1);
    }
    return s;
}

public static void main(String[] args) throws IOException {

    long startTime = System.nanoTime();
    System.out.println("-------------- Start Contents of file: ---------------------");
    FileInputStream inputStream = null;
    Scanner sc = null;
    String path = "C:/xampp/htdocs/thesis_freqeuncy_2/nahidd_filtered.txt";
    try {
        inputStream = new FileInputStream(path);
        sc = new Scanner(inputStream, "UTF-8");
        int countWord = 0;
        BufferedWriter writer = null;
        while (sc.hasNextLine()) {
            String word = null;
            String line = sc.nextLine();
            String[] wordList = line.split("\\s+");

            for (int i = 0; i < wordList.length; i++) {
                word = wordList[i].replace("।", "");
                word = word.replace(",", "").trim();
                ArrayList<String> freqword = new ArrayList<>();
                String freq = fileToString("C:/xampp/htdocs/thesis_freqeuncy_2/freq3.txt");
                /*freqword = freq.split("\\r?\\n");*/
                Collections.addAll(freqword, freq.split("\\r?\\n"));
                int flag = 0;
                String[] freqwordsp = null;
                int k;
                for (k = 0; k < freqword.size(); k++) {
                    freqwordsp = freqword.get(k).split("\\s+");
                    String word2 = freqwordsp[0];
                    word = removeUTF8BOM(word);
                    word2 = removeUTF8BOM(word2);
                    word.replaceAll("\\P{Print}", "");
                    word2.replaceAll("\\P{Print}", "");
                    if (word2.toString().equals(word.toString())) {

                        flag = 1;
                        break;
                    }
                }

                int count = 0;
                if (flag == 1) {
                    count = Integer.parseInt(freqwordsp[1]);
                }
                count = count + 1;
                word = word + " " + count + "\n";
                freqword.add(word);

                System.out.println(freqword);
                writer = new BufferedWriter(new FileWriter("C:/xampp/htdocs/thesis_freqeuncy_2/freq3.txt"));
                writer.write(String.valueOf(freqword));
            }
        }
        // writer.close();
        System.out.println(countWord);
        System.out.println("-------------- End Contents of file: ---------------------");
        long endTime = System.nanoTime();
        long totalTime = (endTime - startTime);
        System.out.println(TimeUnit.MINUTES.convert(totalTime, TimeUnit.NANOSECONDS));

        // note that Scanner suppresses exceptions
        if (sc.ioException() != null) {
            throw sc.ioException();
        }
    } finally {
        if (inputStream != null) {
            inputStream.close();
        }
        if (sc != null) {
            sc.close();
        }
    }

}

}

1 Ответ

0 голосов
/ 01 марта 2019

Прежде всего:

для каждого разбитого слова прочитайте весь частотный файл freq3.txt

Не делайте этого!Операции дискового ввода-вывода очень и очень медленные.Достаточно ли у вас памяти для чтения файла в память?Кажется, да:

String freq = fileToString("C:/xampp/htdocs/thesis_freqeuncy_2/freq3.txt");
Collections.addAll(freqword, freq.split("\\r?\\n"));

Если вам действительно нужен этот файл, загрузите его один раз и работайте с памятью.Также в этом случае карта (от слова к частоте) может быть более удобной, чем список.Сохраните коллекцию на диске, когда вычисления будут сделаны.

Далее вы можете буферизовать ваш входной поток, это может значительно улучшить производительность:

inputStream = new BufferedInputStream(new FileInputStream(path));

И не забудьте закрыть поток / считыватель / запись,Явно или с помощью оператора try-with-resource .

Вообще говоря, код может быть упрощен в зависимости от используемого API.Например:

public class DemoApplication {

    public static final String UTF8_BOM = "\uFEFF";

    private static String removeUTF8BOM(String s) {
        if (s.startsWith(UTF8_BOM)) {
            s = s.substring(1);
        }
        return s;
    }

    private static final String PATH = "words.txt";

    private static final String REGEX = " ";

    public static void main(String[] args) throws IOException {

        Map<String, Long> frequencyMap;
        try (BufferedReader reader = new BufferedReader(new FileReader(PATH))) {
            frequencyMap = reader
                    .lines()
                    .flatMap(s -> Arrays.stream(s.split(REGEX)))
                    .map(DemoApplication::removeUTF8BOM)
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        }

        frequencyMap
                .entrySet()
                .stream()
                .sorted(Comparator.comparingLong(Map.Entry::getValue))
                .limit(20)
                .forEach(System.out::println);
    }
}
...