Search code examples
javasolrsolrj

Solrj: getting MoreLikeThis as beans


Using Solrj it is possible to read Documents from a QueryResponse as (annotated) beans:

List<Item> items = queryResponse.getBeans(Item.class)  

Where Item is the annotated class that maps to a Solr Document.

Now I query for a single document and ask for 10 MoreLikeThis documents:

?q=id:AZ133007&mlt=true&mlt.fl=technique,subject&mlt.mindf=1&mlt.mintf=1&mlt.count=10

This returns the document with id AZ133007 together with 10 'MoreLikeThis' documents (i.e. more like AZ133007 with regard to fields 'technique' and 'subject'). See the (simplified) response below:

<response>

<lst name="responseHeader">
    ...
</lst>

<result name="response" numFound="1" start="0">

    <doc>
        <str name="id">AZ133007</str>
        <str name="title">Still I</str>
        <str name="artist">A.R. Tist</str>
        <str name="technique">Watercolor</str>
        <str name="subject">Still life</str>
    </doc>

</result>

<lst name="moreLikeThis">

    <result name="AZ133007" numFound="84" start="0">

        <doc>
            <str name="id">AZ002001</str>
            <str name="title">Cubes</str>
            <str name="artist">John Doe</str>
            <str name="technique">Watercolor</str>
            <str name="subject">Landscape</str>
        </doc>

        <doc>
            <str name="id">AZ002002</str>
            <str name="title">Cats and Dogs</str>
            <str name="artist">A. Nothername</str>
            <str name="technique">Watercolor</str>
            <str name="subject">Cityscape</str>
        </doc>

        ...

    </result>

</lst>

</response>

The requested document AZ133007 in the response section can be returned as an Item bean like so:

Item item = queryResponse.getBeans(Item.class).get(0);

But how do I get the documents listed under 'moreLikeThis' as beans?


Solution

  • After a lot of experimenting, browsing the web and digging into the Solrj API I came with the following solution. There may be better ways to do it, I would really like to know.

    First extract the moreLikeThis section from the response and cast it to a NamedList:

    NamedList mlt = (NamedList) queryResponse.getResponse().get("moreLikeThis");
    

    Inspecting the NamedList mlt while debugging, it shows the AZ133007 entry along with the SolrDocuments that are 'moreLikeThis'.

    {
        AZ133007={
            numFound=295,
            start=0,
            docs=[
                SolrDocument{
                    id=AZ002001,
                    title=Cubes,
                    artist=JohnDoe,
                    technique=Watercolor,
                    subject=Landscape
                },
                SolrDocument{
                    id=AZ002002,
                    title=CatsAndDogs,
                    artist=A.Nothername,
                    technique=Watercolor,
                    subject=Cityscape
                },
    
                ...
    
            ]
         }
      }
    

    Now get a SolrDocumentList providing the id:

    SolrDocumentList mltDocList = (SolrDocumentList) mlt.get("AZ133007");
    

    And bind this SolrDocumentList to beans:

    DocumentObjectBinder b = new DocumentObjectBinder();
    List<Item> similarItems = b.getBeans(Item.class, mltDocList);
    

    Of course I didn't hard-code the id and I'd built in some null checks, but you get the idea.