Search code examples
scalasolrplayframeworkplayframework-2.1solrj

Call Solr asynchronous from Play Framework


I have created a Play 2.1 Scala application. I am uncertain what's the best way to call Solr from a Play application:

  • There is no Solr module for Play 2.
  • AFAIK all Solr-APIs like SolrJ are blocking.
  • I could wrap a SolrJ call into a Future, but this will also block a thread, correct?
  • Should I use the play.api.libs.ws.WS library to call Solr and use Plays JSON support to extract the result (like in the example below) or is there any easier/faster way?

    val solrQuery: Future[play.api.libs.ws.Response] = WS.url("http://localhost:8983/solr/collection1/select?q=id%3A123&wt=json").get()
    

Solution

  • Here's how I use WS in my side project:

    val itselfNodeFuture = Statix.doParams( Statix.SolrSelectWSReq, 
        List(
        "wt"     -> "json", 
        "q"      -> "*:*",
        "fq"     -> "node_type:collection",
        "fq"     -> "id:%d".format( nodeId),
        "indent" -> "true",
        "rows"   -> "1",
        "fl"     -> "id,parent_id,title",
        "fl"     -> "date_created,date_about,date_modified")
    ).get()
    
    //Use the first Await after the last future
    val itselfJson = Await.result(
        itselfNodeFuture, Duration("2 sec")).json
    
    val mainRow = (itselfJson \ "response" \ "docs").as[ Seq[JsValue]]
    val mainNodeParent = (mainRow(0) \ "parent_id").as[Long]
    val mainNodeTitle = (mainRow(0) \ "title").as[String]
    

    And here's the utility class I use, the doParams is especially useful.

    object Statix { //Noder must extend this
        def SolrSelectWSReq = WS.url("http://127.0.0.1:8080/solr-store/collection1/select/")
        def SolrUpdateWSReq = WS.url("http://127.0.0.1:8080/solr-store/collection1/update/json/")
    
        def doParams(request: WS.WSRequestHolder, params: List[(String, String)]) = {
            params.foldLeft( request){
                (wsReq, tuple) => wsReq.withQueryString( tuple)}}
    }