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. В чем может быть причина ошибки и как ее устранить?


person XieWilliam    schedule 25.07.2017    source источник


Ответы (2)


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

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

Поскольку возвращаемый '_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.

Скопируйте jar-файлы (импортер mongo solr и драйвер mongo-java) в каталог 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>

Управляемая схема будет иметь поле идентификатора в виде строки. Кроме того, если у вас есть вложенные объекты в mongodb, вам придется использовать преобразователи сценариев для их индексации в solr.

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

person Pruthvik Narayanaswamy    schedule 08.09.2017

Согласно сообщению об ошибке,

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

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

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

После написания реализации JavaBinCodec.ObjectResolver ее необходимо зарегистрировать с помощью JavaBinCodec.

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

открытый класс JavaBinCodec extends Object Определяет компактный формат сериализации/десериализации для передачи данных. JavaBinCodec имеет встроенную поддержку многих часто используемых типов. Сюда входят примитивные типы (boolean, byte, short, double, int, long, float), распространенные контейнеры/утилиты Java (Date, Map, Collection, Iterator, String, Object[], byte[]) и часто используемые типы Solr. (ИменованныйСписок, SolrDocument, SolrDocumentList). Каждый из вышеперечисленных типов имеет пару связанных методов, которые читают и записывают этот тип в поток.

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

ПРИМЕЧАНИЕ. Экземпляры JavaBinCodec нельзя повторно использовать более чем для одной операции маршалла или демаршалла.

person Kerem Baydoğan    schedule 04.08.2017
comment
OP, похоже, использует коннектор mongo, который широко используется для импорта данных из mongodb без какой-либо дополнительной реализации. - person Rajesh; 04.08.2017