Java 使用hadoop reducer将BulkWriteOperation写入mongo时检查重复记录
我正在使用hadoop map reduce处理XML文件。我正在将JSON数据直接存储到mongodb中。Java 使用hadoop reducer将BulkWriteOperation写入mongo时检查重复记录,java,mongodb,hadoop,mapreduce,bulkinsert,Java,Mongodb,Hadoop,Mapreduce,Bulkinsert,我正在使用hadoop map reduce处理XML文件。我正在将JSON数据直接存储到mongodb中。在执行BulkWriteOperation之前,如何实现只将非重复记录存储到数据库中 重复记录标准将基于产品图像和产品名称,我不想使用morphia的层,在该层中我们可以为类成员分配索引 这是我的减速机课程: public class XMLReducer extends Reducer<Text, MapWritable, Text, NullWritable>{ priv
在执行
BulkWriteOperation
之前,如何实现只将非重复记录存储到数据库中
重复记录标准将基于产品图像和产品名称,我不想使用morphia的层,在该层中我们可以为类成员分配索引
这是我的减速机课程:public class XMLReducer extends Reducer<Text, MapWritable, Text, NullWritable>{
private static final Logger LOGGER = Logger.getLogger(XMLReducer.class);
protected void reduce(Text key, Iterable<MapWritable> values, Context ctx) throws IOException, InterruptedException{
LOGGER.info("reduce()------Start for key>"+key);
Map<String,String> insertProductInfo = new HashMap<String,String>();
try{
MongoClient mongoClient = new MongoClient("localhost", 27017);
DB db = mongoClient.getDB("test");
BulkWriteOperation operation = db.getCollection("product").initializeOrderedBulkOperation();
for (MapWritable entry : values) {
for (Entry<Writable, Writable> extractProductInfo : entry.entrySet()) {
insertProductInfo.put(extractProductInfo.getKey().toString(), extractProductInfo.getValue().toString());
}
if(!insertProductInfo.isEmpty()){
BasicDBObject basicDBObject = new BasicDBObject(insertProductInfo);
operation.insert(basicDBObject);
}
}
//How can I check for duplicates before executing bulk operation
operation.execute();
LOGGER.info("reduce------end for key"+key);
}catch(Exception e){
LOGGER.error("General Exception in XMLReducer",e);
}
}
}
我收到的错误如下:com.mongodb.MongoInternalException:未找到索引0的映射
任何帮助都会很有用。谢谢。我想这一切都取决于您对“复制品”的处理方式 例如,您可以始终使用它,它不会在索引中的重复键上“出错”(您需要停止重复),但会在返回的对象中报告任何此类错误。从
.execute()
另一方面,您可以只使用“upserts”代替,并使用运算符,例如仅在不存在重复项的情况下进行更改:
BasicDBObject basicdbobject = new BasicDBObject(insertProductInfo);
BasicDBObject query = new BasicDBObject("key", basicdbobject.get("key"));
operation.find(query).upsert().updateOne(new BasicDBObject("$setOnInsert", basicdbobject));
因此,您基本上是通过查询查找保存“key”的字段的值来确定重复项,然后只实际更改未找到该“key”的任何数据,从而创建一个新文档并“插入”
无论哪种情况,这里的默认行为都是“插入”第一个唯一的“键”值,然后忽略所有其他情况。如果您想在找到相同键的位置执行其他操作,如“覆盖”或“增量”值,那么
.update()
“upsert”方法就是您想要的方法,但您将使用其他方法来执行这些操作。我不明白如何创建查询?我想检查basicdbobject
是否包含insertProductInfo
多个文件。根据产品名称和产品图像,我检查重复记录的标准是否存在于操作中?@Nakul91只有“有限”数量的字段才能真正形成重复记录。然后,如果整个内容不应该存在超过一次,那么只使用您插入的对象作为完整的查询。如果你真的不确定,那么再问另一个问题。但是,你应该在你认为“唯一”的字段中定义一个“唯一”索引。唯一的定义是在这两个字段上定义的。我已经在集合中的这些字段上添加了复合索引,但在使用.initializeUnderedBulkOperation()对5000条记录执行大容量插入时,如果第1001条记录重复,则会引发异常,剩余的4000条记录不会添加到数据库中。据你所说,它不会在复制上出错,但它仍然给出了一个错误error@Nakul91如果您在所示的唯一字段上使用“更新”,则不会。.insert()
操作可能引发重复的密钥错误。搜索唯一属性并使用.update()
“覆盖”或更具体地说,由于$setOnInsert
,因此“不做任何事情”。如果您得到重复的键错误,那么您并不是在查询所有唯一值。@Nakul91我已经给出的答案再清楚不过了。您在文档的“唯一”字段上进行“查询”,并且.update()
操作“不可能”生成重复项。答案是正确的,但您的编码似乎有问题。如果您仍然无法理解,请针对您遇到的任何进一步困难发布另一个问题。这个答案将不再有对应关系,因为它本身是完全正确的。
BulkWriteResult result = operation.execute();
BasicDBObject basicdbobject = new BasicDBObject(insertProductInfo);
BasicDBObject query = new BasicDBObject("key", basicdbobject.get("key"));
operation.find(query).upsert().updateOne(new BasicDBObject("$setOnInsert", basicdbobject));