Org.apache.solr.common.SolrException: TransactionLog не знает, как сериализовать класс org.bson.types.ObjectId; попробуйте реализовать ObjectResolver?

При выполнении импорта данных из 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. Что может быть причиной ошибки и как ее можно решить?

Ответ 1

Я столкнулся с этой проблемой при попытке импортировать данные из нескольких коллекций в mongoDB.

Предполагая, что вы не используете mongo-коннектор, я использовал следующее для импорта данных.

Так как возвращенный "_id" имеет тип ObjectId, моя работа вокруг решения заключалась в том, чтобы преобразовать "_id" в String, прежде чем индексировать его в solr и при запросе в отношении "_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.

Скопируйте банки (импортер solr mongo и mongo-java-driver) в каталог lib. Я скопировал их в ${solr-install-dir}/contrib/dataimport-handler/lib

Добавьте директивы lib в файл solr-config.xml для указанных выше банок:

<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 = "true" для поля _id, чтобы MongoMapperTransformer мог форматировать идентификатор.

<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, вам придется использовать трансформаторы script, чтобы индексировать их в solr.

Надеюсь, это поможет, Удачи!

Ответ 2

В соответствии с сообщением об ошибке

Вам нужно реализовать JavaBinCodec.ObjectResolver для org.bson.types.ObjectId, поэтому Solr будет знать, как сериализовать экземпляры этого класса.

Документация JavaBinCodec.ObjectResolver

открытый статический интерфейс JavaBinCodec.ObjectResolver Позволяет расширение JavaBinCodec для поддержки сериализации произвольных типов данных. Разработчики этого интерфейса пишут метод сериализации заданного объект с использованием существующего JavaBinCodec

После того, как вы напишете реализацию JavaBinCodec.ObjectResolver, вы должны зарегистрировать ее с помощью JavaBinCodec

Документация JavaBinCodec

открытый класс JavaBinCodec extends Object Определяет экономичность пространства формат сериализации/десериализации для передачи данных. JavaBinCodec имеет встроенную поддержку многих часто используемых типов. Эта включает примитивные типы (булевы, байты, короткие, двойные, int, long, float), общие контейнеры/утилиты Java (дата, карта, коллекция, Iterator, String, Object [], byte []) и часто используемые типы Solr (NamedList, SolrDocument, SolrDocumentList). Каждый из указанных типов имеет пару связанных методов, которые считывают и записывают этот тип в поток.

Классы, которые не поддерживаются изначально, все еще могут быть сериализован/десериализован, предоставляя JavaBinCodec.ObjectResolver объект, который знает, как работать с неподдерживаемым классом. Это позволяет JavaBinCodec используется для сортировки и отмены произвольного содержимого.

ПРИМЕЧАНИЕ. - экземпляры JavaBinCodec нельзя использовать повторно для нескольких marshall или unmarshall.