org.apache.solr.common.SolrException:TransactionLog不知道如何序列化类org.bson.types.ObjectId;尝试实现ObjectResolver?

时间:2017-07-25 02:26:06

标签: mongodb solr dataimporthandler

从mongodb执行数据导入时,Solr会抛出以下错误:

org.apache.solr.common.SolrException: TransactionLog doesn't know how to serialize class org.bson.types.ObjectId; try implementing ObjectResolver?
at org.apache.solr.update.TransactionLog$1.resolve(TransactionLog.java:100)
at org.apache.solr.common.util.JavaBinCodec.writeVal(JavaBinCodec.java:234)
at org.apache.solr.common.util.JavaBinCodec.writeSolrInputDocument(JavaBinCodec.java:589)
at org.apache.solr.update.TransactionLog.write(TransactionLog.java:395)
at org.apache.solr.update.UpdateLog.add(UpdateLog.java:532)
at org.apache.solr.update.UpdateLog.add(UpdateLog.java:516)
at org.apache.solr.update.DirectUpdateHandler2.doNormalUpdate(DirectUpdateHandler2.java:320)
at org.apache.solr.update.DirectUpdateHandler2.addDoc0(DirectUpdateHandler2.java:239)
at org.apache.solr.update.DirectUpdateHandler2.addDoc(DirectUpdateHandler2.java:194)
at org.apache.solr.update.processor.RunUpdateProcessor.processAdd(RunUpdateProcessorFactory.java:67)
at org.apache.solr.update.processor.UpdateRequestProcessor.processAdd(UpdateRequestProcessor.java:55)
at org.apache.solr.update.processor.DistributedUpdateProcessor.doLocalAdd(DistributedUpdateProcessor.java:979)
at org.apache.solr.update.processor.DistributedUpdateProcessor.versionAdd(DistributedUpdateProcessor.java:1192)
at org.apache.solr.update.processor.DistributedUpdateProcessor.processAdd(DistributedUpdateProcessor.java:748)
at org.apache.solr.update.processor.LogUpdateProcessorFactory$LogUpdateProcessor.processAdd(LogUpdateProcessorFactory.java:103)
at org.apache.solr.handler.dataimport.SolrWriter.upload(SolrWriter.java:80)
at org.apache.solr.handler.dataimport.DataImportHandler$1.upload(DataImportHandler.java:254)
at org.apache.solr.handler.dataimport.DocBuilder.buildDocument(DocBuilder.java:526)
at org.apache.solr.handler.dataimport.DocBuilder.buildDocument(DocBuilder.java:414)
at org.apache.solr.handler.dataimport.DocBuilder.doFullDump(DocBuilder.java:329)
at org.apache.solr.handler.dataimport.DocBuilder.execute(DocBuilder.java:232)
at org.apache.solr.handler.dataimport.DataImporter.doFullImport(DataImporter.java:415)
at org.apache.solr.handler.dataimport.DataImporter.runCmd(DataImporter.java:474)
at org.apache.solr.handler.dataimport.DataImporter.lambda$runAsync$0(DataImporter.java:457)
at java.lang.Thread.run(Thread.java:748)

我的Solr版本是6.6.0。可能是错误的原因以及如何解决?

2 个答案:

答案 0 :(得分:2)

我在尝试从mongoDB中的多个集合中导入数据时遇到了这个问题。

假设您没有使用mongo-connector,我使用以下内容导入数据。

自返回的' _id'是ObjectId类型,我的解决方案是转换' _id'在将其索引到solr之前进行String,并在查询' _id'时,在运行查询之前将其转换为ObjectId类型。

下载solr mongo导入程序并进行以下更改。

MongoMapperTransformer.java

public class MongoMapperTransformer extends Transformer {

@Override
public Object transformRow(Map<String, Object> row, Context context) {

    for (Map<String, String> map : context.getAllEntityFields()) {
        String mongoFieldName = map.get(MONGO_FIELD);
        String mongoId = map.get(MONGO_ID);
        if (mongoFieldName == null)
            continue;

        String columnFieldName = map.get(DataImporter.COLUMN);

        //If the field is ObjectId convert it into String
        if (mongoId != null && Boolean.parseBoolean(mongoId)) {
            Object srcId = row.get(columnFieldName);
            row.put(columnFieldName, srcId.toString());
        }
        else{
            row.put(columnFieldName, row.get(mongoFieldName));
        }
    }

    return row;
}


public static final String MONGO_FIELD = "mongoField";

//To identify the _id field
public static final String MONGO_ID = "objectIdToString";

}

接下来,替换功能

public Iterator <Map<String, Object>> getData(String query){...} 
在MongoDataSource.java中使用以下代码

@Override
public Iterator<Map<String, Object>> getData(String query) {

    DBObject queryObject = new BasicDBObject();

    /* If querying by _id, since the id is a string now, 
     * it has to be converted back to type ObjectId() using the 
     * constructor 
     */ 
    if(query.contains("_id")){
        @SuppressWarnings("unchecked")
        Map<String, String> queryWithId = (Map<String, String>) JSON.parse(query);
        String id = queryWithId.get("_id");
        queryObject = new BasicDBObject("_id", new ObjectId(id));
    }
    else{
        queryObject = (DBObject) JSON.parse(query);
    }

    LOG.debug("Executing MongoQuery: " + query.toString());

    long start = System.currentTimeMillis();
    mongoCursor = this.mongoCollection.find(queryObject);
    LOG.trace("Time taken for mongo :"
            + (System.currentTimeMillis() - start));

    ResultSetIterator resultSet = new ResultSetIterator(mongoCursor);
    return resultSet.getIterator();
}

完成这些更改后,您可以使用ant构建jar。

将jar(solr mongo importer和mongo-java-driver)复制到lib目录中。我将它们复制到$ {solr-install-dir} / contrib / dataimport-handler / lib

在solr-config.xml中为上述jar添加lib指令:

<lib dir="${solr.install.dir:../../../..}/contrib/dataimporthandler/lib" regex=".*\.jar" />

最后,这是mongo集合和data-config.xml

的示例
User collection
{
    "_id" : ObjectId("56e9c892e4b0355017b2fa0f"),
    "name" : "User1",
    "phone" : "123456789"
}

Address collection
{
    "_id" : ObjectId("56e9c892e4b0355017b2fa0f"),
    "address" : "#666, Maiden street"
}

数据-config.xml中

别忘了提及objectIdToString =&#34; true&#34;对于_id字段,以便MongoMapperTransformer可以对id进行字符串化。

<dataConfig>
   <dataSource name="MyMongo"
           type="MongoDataSource"
           database="test"
            />
   <document name="UserDetails">
   <!-- if query="" then it imports everything -->
      <entity name="users"
          processor="MongoEntityProcessor"
          query=""
          collection="user"
          datasource="MyMongo"
          transformer="MongoMapperTransformer">
              <field column="_id"  name="id" mongoField="_id" objectIdToString="true" />
              <field column="phone" name="phone" mongoField="phone"/>

          <entity name="address"
                processor="MongoEntityProcessor"
                query="{_id:'${users._id}'}"
                collection="address"
                datasource="MyMongo"
                transformer="MongoMapperTransformer">
                <field column="address" name="adress" mongoField="address"/>
          </entity>
   </entity>
   </document>
</dataConfig>

托管架构将id字段作为字符串。 此外,如果您在mongodb中有嵌套对象,则必须使用脚本转换器在solr中对它们进行索引。

希望这有帮助, 祝你好运!

答案 1 :(得分:1)

根据错误消息,

您需要为org.bson.types.ObjectId类型实现 JavaBinCodec.ObjectResolver ,因此Solr将知道如何序列化此类的实例。

JavaBinCodec.ObjectResolver Documentation

  

public static interface JavaBinCodec.ObjectResolver允许扩展名   JavaBinCodec支持任意数据类型的序列化。   此接口的实现者编写一个序列化给定的方法   使用现有JavaBinCodec

的对象

编写 JavaBinCodec.ObjectResolver 实现后,应使用 JavaBinCodec

进行注册

JavaBinCodec Documentation

  

public class JavaBinCodec extends Object定义节省空间   用于传输数据的序列化/反序列化格式。   JavaBinCodec内置了许多常用类型。这个   包括原始类型(boolean,byte,short,double,int,long,   常见的Java容器/实用程序(日期,地图,集合,   Iterator,String,Object [],byte [])和常用的Solr类型   (NamedList,SolrDocument,SolrDocumentList)。以上各种类型   有一对相关的方法,可以读取和写入该类型   流。

     

本机不支持的类仍然可以   通过提供JavaBinCodec.ObjectResolver进行序列化/反序列化   知道如何使用不受支持的类的对象。这允许   JavaBinCodec用于编组/解组任意内容。

     

注意 - JavaBinCodec实例不能重复使用多个实例   马歇尔或解散操作。