2013-06-24 33 views
3

我創建了Play 2.1 Scala應用程序。我不清楚什麼是從Play應用程序調用的Solr的最佳方式:從Play Framework異步調用Solr

  • 沒有爲播放2
  • 據我所知所有的Solr的API,如SolrJ是阻止任何Solr的模塊。
  • 我可以將SolrJ調用包裝爲Future,但這也會阻塞一個線程,是否正確?
  • 我應該使用play.api.libs.ws.WS庫調用Solr並使用Plays JSON支持來提取結果(如下面的示例中所示)還是有更簡單/更快的方法?

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

你可以考慮使用Dispatch或Spray,因爲它們都是在Netty之上構建的,並且在發出http請求時完全是NIO。 – cmbaxter

+0

謝謝,但是爲什麼Dispatch或Spray會比Web服務庫'WS'更好? – Sonson123

+1

我不確定ws api正在做什麼。即使它返回未來,我也不確定在進行http調用時它是否仍在阻止io。我會研究這一點,如果它的尼奧如果你已經在使用遊戲,那麼這可能是一個不錯的選擇。如果沒有,那麼你可以看看我提到的庫。 – cmbaxter

回答

2

以下是我在我的身邊的項目中使用WS:

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] 

而這裏的實用工具類我使用的doParams特別有用。

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)}} 
} 
+0

有趣,謝謝。我將在您的示例中啓動基於WS的非阻塞Solr客戶端。 – Sonson123

1

你想包裝在未來的呼叫與自己Execution context。這樣調用可能會阻塞,但它將使用不同的線程池,而不會阻塞主應用程序。

事實上,這是面對阻塞或緩慢任務時的標準行爲,如將查詢發送到數據庫或執行一些繁重的任務。

+0

謝謝,我不知道。 – Sonson123

1

最近遇到了這個需求,並沒有發現任何有用的谷歌搜索。以下僅供查詢,但可以擴展。我假設你想留在SolrJ類。 SolrQuery和QueryResponse很容易處理。

所以要查詢。您將需要像平常一樣構建SolrQuery。爲「wt」提供「javabin」。這會給你一個SolrJ內部使用的壓縮二進制格式的響應。

val sq = new SolrQuery() 
sq.set("wt", "javabin") 
... 

您會想要將您的SolrQuery轉換爲WS理解的內容。 (我還沒有添加所有的進口,因爲大多數是直接找出[例如,你的IDE。這些我已經包括可能不那麼明顯了。)

import scala.collection.JavaConverters._ 

def solrQueryToForm(sq: SolrQuery): Map[String, Seq[String]] = { 
    sq.getParameterNames.asScala.foldLeft(Map.empty[String, Seq[String]]) { 
    case (m, n) => 
     m + (n -> sq.getParams(n)) 
    } 
} 

在我的店裏,我們使用默認集合和處理器(即「/選擇」),但你會想那些由SolrQuery

def solrEndpoint(sq: SolrQuery): String = { 
    val coll = sq.get("collection", defaultCollection) 
    val hand = Option(sq.getRequestHandler).getOrElse(defaultHandler) 
    formSolrEndpoint(solrUrl, coll, hand) 
} 

def formSolrEndpoint(base: String, collection: String, handler: String): String = { 
    val sb = new StringBuilder(base) 
    if (sb.last != '/') sb.append('/') 
    sb.append(collection) 
    if (!handler.startsWith("/")) sb.append('/') 
    sb.append(handler) 
    sb.result() 
} 

你需要一些代碼到WSResponse映射到QueryResponse

import com.ning.http.client.{Response => ACHResponse} 

def wsResponseToQueryResponse(wsResponse: WSResponse)(implicit ctx: ExecutionContext): QueryResponse = { 
    val jbcUnmarshal = { 
    val rbis = wsResponse.underlying[ACHResponse].getResponseBodyAsStream 

    try { 
     new JavaBinCodec().unmarshal(rbis) 
    } 
    finally { 
     if (rbis != null) 
     rbis.close() 
    } 
    } 

    // p1: SolrJ pulls the same cast 
    // p2: We didn't use a SolrServer to chat with Solr so cannot provide it to QueryResponse 
    new QueryResponse(jbcUnmarshal.asInstanceOf[NamedList[Object]], null) 
} 

而且覆蓋那個giv您可以使用Play的異步WS服務調用Solr。

def query(sq: SolrQuery)(implicit ctx: ExecutionContext): Future[QueryResponse] = { 
    val sqstar = sq.getCopy 
    sqstar.set("wt", "javabin") 

    WS.url(solrEndpoint(sqstar)) 
    .post(solrQueryToForm(sqstar)) 
    .map(wsResponseToQueryResponse) 
} 

由於現在遊戲發佈web服務的代碼作爲一個獨立的罐子,這意味着幾乎所有的項目應該能夠查詢Solr的異步。希望這很有用。

+0

謝謝,看起來不錯。我無法測試它,因爲在我當前的項目中,我最終從Solr切換到Elasticsearch(使用異步API)。 – Sonson123