Solr document Custom mapping depending on type

365 views Asked by At

I have a SOLR server serving information on 3 types of entities that share some information in common. For many reasons, I decided to store all the information in the same core.

Using solr data spring, I'm trying to transfer the document information from the SOLR server into 3 types of entities inheritance model:

@SolrDocument(solrCoreName = "core")
open class Item {
  common fields
  type : String = "",
  open var secondaryFields: Map<String, List<String>>? = null
}

@SolrDocument(solrCoreName = "core")
class A ( 
   @Indexed("a_*")
   override var secondaryFields: Map<String, List<String>>? = null
) : Item()

@SolrDocument(solrCoreName = "core")
class B (
  @Indexed("b_*")
  override var secondaryFields: Map<String, List<String>>? = null
) : Item()
...
class C(...)

This was working just fine, until I tried to search over all documents. Since the specific class depends on the object type, and they are mapped to Item by default, the attribute secondaryFields is obviously not filled with the corresponding information so secondaryFields is always null.

I guess I would have to implement a custom mapping between the returned SOLR document and the class itself? Is it possible?

1

There are 1 answers

0
adrian On

I will answer myself here. I'm not sure if this is the most efficient solution but at least it worked for me.

I added a custom Converter to solrConverter within my SolrConfig class:

@Configuration
@EnableSolrRepositories (basePackages = ["base"])
@ComponentScan
class SolrConfig {

    @Bean
    fun solrClientFactory() : SolrClientFactory {
        return SolrClientFactory { HttpSolrClient.Builder("http://localhost:8983/solr").build() }
    }

    @Bean
    fun customConversions(): CustomConversions? {
        return SolrCustomConversions(arrayListOf(ItemConverter, AConverter, BConverter))
    }

    @Bean
    fun solrConverter(customConversions: CustomConversions): SolrConverter? {
        val solrConverter = MappingSolrConverter(SimpleSolrMappingContext())
        solrConverter.setCustomConversions(customConversions)
        return solrConverter
    }

    @Bean
    @Throws(java.lang.Exception::class)
    fun solrTemplate(clientFactory: SolrClientFactory, solrConverter: SolrConverter) : SolrTemplate {
        return SolrTemplate(clientFactory, solrConverter)
    }
}

The converters are as follows:

@ReadingConverter
object ItemConverter : Converter<SolrDocument, Item> {
    override fun convert(source: SolrDocument): Item {
        val mappingSolrConverter = MappingSolrConverter(SimpleSolrMappingContext())
        if (source.getFieldValue("type") == companion.A_TYPE) {
            return mappingSolrConverter.read(A::class.java, source)
        }
        if (source.getFieldValue("type") == companion.B_TYPE) {
            return mappingSolrConverter.read(B::class.java, source)
        }
        return mappingSolrConverter.read(Item::class.java, source)
    }
}
@ReadingConverter
object AConverter : Converter<SolrDocument, A> {
    override fun convert(source: SolrDocument): A {
        val mappingSolrConverter = MappingSolrConverter(SimpleSolrMappingContext())
        return mappingSolrConverter.read(A::class.java, source)
    }
}

And so on. So basically what I'm doing is calling the default MappingSolrConverter but reading the appropiate subclass depending on the field "type".