使用hadoop reducer检查BulkWriteOperation进入mongo时的重复记录

时间:2015-06-26 05:55:25

标签: java mongodb hadoop mapreduce bulkinsert

我正在使用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

任何帮助都会有用。谢谢。

1 个答案:

答案 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来实现那些行动。