我正在使用hadoop map-reduce处理XML文件。我直接将JSON数据存储到mongodb中。
如何才能实现在执行BulkWriteOperation
之前只将非重复记录存储到数据库中?
重复记录条件将基于产品图片和产品名称,我不想使用图层,我们可以为类成员分配索引
这是我的减速机类:
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);
}
}
}
编辑:在建议的答案之后我添加了:
BasicDBObject query = new BasicDBObject("product_image", basicDBObject.get("product_image"))
.append("product_name", basicDBObject.get("product_name"));
operation.find(query).upsert().updateOne(new BasicDBObject("$setOnInsert", basicDBObject));
operation.insert(basicDBObject);
我收到的错误如下:com.mongodb.MongoInternalException: no mapping found for index 0
任何帮助都会有用。谢谢。
答案 0 :(得分:1)
我想这一切都取决于你真正想要用“重复”做什么来处理它。
对于其中一个,您始终可以使用.initializeUnOrderedBulkOperation()
对索引中的重复键(您需要停止重复)不会出现“错误”,但会在返回的BulkWriteResult
中报告任何此类错误宾语。哪个是从.execute()
BulkWriteResult result = operation.execute();
另一方面,您可以改为使用“upserts”,并使用$setOnInsert
等运算符仅在不存在重复的情况下进行更改:
BasicDBObject basicdbobject = new BasicDBObject(insertProductInfo);
BasicDBObject query = new BasicDBObject("key", basicdbobject.get("key"));
operation.find(query).upsert().updateOne(new BasicDBObject("$setOnInsert", basicdbobject));
因此,您基本上查找包含“密钥”的字段的值以确定查询的副本,然后仅实际更改未找到该“密钥”的任何数据,从而更新新文档并“插入”
在任何一种情况下,此处的默认行为是“插入”第一个唯一的“键”值,然后忽略所有其他出现。如果你想做其他事情,比如找到相同键的“覆盖”或“递增”值,那么.update()
“upsert”方法就是你想要的方法,但你会使用其他update operators来实现那些行动。