Java 使用hadoop reducer将BulkWriteOperation写入mongo时检查重复记录

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

我正在使用hadoop map reduce处理XML文件。我正在将JSON数据直接存储到mongodb中。
在执行
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));