Как удалить разрывы строк и пустые строки из строки - PullRequest
0 голосов
/ 21 января 2019

Я пытаюсь запустить задание mapreduce на hadoop, который читает пятую запись файла с разделителями табуляции (пятая запись - обзоры пользователей), а затем выполняет некоторый анализ настроений и подсчет слов на них.

Однако,как вы знаете из отзывов пользователей, они обычно включают разрывы строк и пустые строки.Мой код перебирает слова каждого отзыва, чтобы найти ключевые слова и проверить настроение, если ключевое слово найдено.

Проблема в том, что код повторяет обзор, он выдает мне ArrayIndexOutofBoundsException Ошибка из-за этих разрывов строк и пустых строк в одном обзоре.

Я пытался использовать replaceAll("\r", " ") иreplaceAll("\n", " ") безрезультатно.

Я тоже пробовал if(tokenizer.countTokens() == 2){ word.set(tokenizer.nextToken());} else { }

тоже безрезультатно.Ниже приведен мой код:

public class KWSentiment_Mapper extends Mapper<LongWritable, Text, Text, IntWritable> {
ArrayList<String> keywordsList = new ArrayList<String>();
ArrayList<String> posWordsList = new ArrayList<String>();
ArrayList<String> tokensList = new ArrayList<String>();
int e;

@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

    String[] line = value.toString().split("\t");
    String Review = line[4].replaceAll("[\\-\\+\\\\)\\.\\(\"\\{\\$\\^:,]", "").toLowerCase();

    StringTokenizer tokenizer = new StringTokenizer(Review);

    while (tokenizer.hasMoreTokens()) {
        // 1- first read the review line and store the tokens in an arraylist, 2-
        // iterate through review to check for KW if found
        // 3-check if there's PosWord near (upto +3 and -2)
        // 4- setWord & context.write 5- null the review line arraylist
        String CompareString = tokenizer.nextToken();

        tokensList.add(CompareString);
    }
    {
    for (int i = 0; i < tokensList.size(); i++)

    {

        for (int j = 0; j < keywordsList.size(); j++) {
            boolean flag = false;

            if (tokensList.get(i).startsWith(keywordsList.get(j)) == true) {

                for (int e = Math.max(0, i - 2); e < Math.min(tokensList.size(), i + 4); e++) {

                    if (posWordsList.contains(tokensList.get(e))) {

                        word.set(keywordsList.get(j));
                        context.write(word, one);
                        flag = true;

                        break; // breaks out of e loop }}
                    }
                }
            }
            if (flag)
                break;
        }
    }
    tokensList.clear();
}

}

Ожидаемые результаты таковы: Возьмите эти два случая обзоров, где возникает ошибка:

Случай 1: «Красивый и просторный!
Я очень рекомендую это место и замечательного хозяина. "

Случай 2:" В целом место было действительно тихим, но мы не чувствовали себя оставленными.

Помимо этого,ванная комната большая, а душ действительно хороший, но есть проблема. "

Система должна прочитать весь обзор одной строкой и перебрать слова в нем.Однако, он просто останавливается, когда находит разрыв строки или пустую строку, как в случае 2.
Случай 1 следует читать так: «Красиво и просторно! Я очень рекомендую это место и замечательного хозяина».

Случай 2 должен звучать так: «В общем, место было действительно тихим, но мы не чувствовали себя оставленными. Кроме этого, ванная комната большая, а душ действительно хороший, но есть проблема».

У меня мало времени, и я очень признателен за помощь.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Проверяйте каждую строку в начале метода map, чтобы вы знали, что line[4] существует и не равно нулю.

if (value == null || value.toString == null) {
    return;
}

String[] line = value.toString().split("\t");
if (line == null || line.length() < 5 || line[4] == null) {
    return;
}

Что касается разрывов строк, вам нужно показать пример ввода. По умолчанию MapReduce передает каждую строку в метод map независимо, поэтому, если вы хотите прочитать несколько строк как одно сообщение, вам придется написать пользовательский InputSplit или предварительно отформатировать данные, чтобы все данные для каждый отзыв в одной строке.

0 голосов
/ 21 января 2019

Итак, я надеюсь, я понимаю, что вы пытаетесь сделать .... Если я правильно читаю то, что у вас есть выше, значение 'value', переданное в вашу функцию карты выше, содержит значение с разделителями, из которого вы хотели бы проанализировать отзывы пользователей. Если это так, я полагаю, что мы можем использовать функцию экранирования в библиотеке opencsv, используя табуляции в качестве символа-разделителя вместо запятых, чтобы правильно заполнить поле обзора пользователя: http://opencsv.sourceforge.net

В этом примере мы читаем одну строку из переданного ввода и анализируем его в «столбцы» на основе символа табуляции и помещаем результаты в массив «nextLine». Это позволит нам использовать экранирующую функциональность CSVReader, не читая фактический файл и вместо этого используя значение текста, переданного в функцию карты.

        StringReader reader = new StringReader(value.toString());
        CSVReader csvReader = new CSVReader(reader, '\t', '\"', '\\', 0);

        String [] nextLine = csvReader.readNext();
        if(nextLine != null && nextLine.length >= 5) {
           // Do some stuff
        }

В примере, который вы вставили выше, я думаю, что даже такое разделение ("\ n") будет проблематичным, поскольку вкладки в пользовательском обзоре разбиваются на два результата в результате в дополнение к новым строкам, которые обрабатываются как новые записи. Но оба эти символа допустимы, если они находятся внутри значения в кавычках (так, как они должны быть в правильно экранированном файле и как в вашем примере). CSVReader должен обрабатывать все это.

...