我正在尝试在hadoop上运行mapreduce作业,该作业读取制表符分隔文件的第五个条目(第五个条目是用户评论),然后对其进行一些情感分析和字数统计。
但是,正如您对用户评论所知,它们通常包括换行符和空行。我的代码遍历每个评论的单词以查找关键字,并检查是否找到关键字。
问题出在代码遍历审阅时,它给了我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种情况应该是:“总的来说,这个地方真的很安静,但我们没有感觉到停留。除此之外,浴室很大,淋浴真的很好,但是有问题。”
我的时间不多了,非常感谢您的帮助。
谢谢!
答案 0 :(得分:0)
所以,我希望我能理解您要做什么。 如果我正确地读取了上面的内容,则传递到上面的map函数中的“值”的值包含您要从中解析出用户评论的定界值。如果是这种情况,我相信我们可以使用制表符作为分隔符(而不是逗号)来使用opencsv库中的转义功能来正确填充用户查看字段: http://opencsv.sourceforge.net
在此示例中,我们从传入的输入中读取一行,并基于制表符将其解析为“列”,并将结果放置在“ nextLine”数组中。这将使我们能够使用CSVReader的转义功能,而无需读取实际文件,而是使用传递到您的map函数中的文本值。
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
}
在您上面粘贴的示例中,我认为即使split(“ \ n”)也会出现问题,因为除了将新行视为新记录之外,用户评论中的选项卡还会分成两个结果。但是,只要这两个字符都位于带引号的值内(因为它们应该在正确转义的文件中,并且与您的示例中的一样),则这两个字符都是合法的。 CSVReader应该处理所有这些。
答案 1 :(得分:0)
在ServerHttpSecurity
方法的开头验证每一行,以使您知道map
存在并且不为空。
line[4]
对于换行符,您需要显示一些示例输入。默认情况下,MapReduce将每一行分别独立地传递到if (value == null || value.toString == null) {
return;
}
String[] line = value.toString().split("\t");
if (line == null || line.length() < 5 || line[4] == null) {
return;
}
方法中,因此,如果您确实想将多行作为一条消息读取,则必须编写自定义map
或对数据进行预格式化,以便每个评论的所有数据都在同一行。