3

Play 2.1 Scala アプリケーションを作成しました。Play アプリケーションから Solr を呼び出す最善の方法がわかりません。

  • Play 2 用の Solr モジュールはありません。
  • 私の知る限り、SolrJ などのすべての Solr-API がブロックされています。
  • SolrJ 呼び出しを にラップすることもできますFutureが、これはスレッドもブロックしますよね?
  • ライブラリを使用してplay.api.libs.ws.WSSolr を呼び出し、Plays JSON サポートを使用して結果を抽出する必要がありますか (以下の例のように)、またはより簡単で高速な方法はありますか?

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

3 に答える 3

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)}}
}
于 2013-06-26T08:24:56.950 に答える
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))
  }
}

私のショップでは、デフォルトのコレクションとハンドラー (つまり、「/select」) を使用していますが、これらを 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)
}

これで、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)
}

Play は Web サービス コードをスタンドアロンの jar として公開するようになったので、これはほとんどすべてのプロジェクトが Solr を非同期的にクエリできることを意味します。それが役に立つことを願っています。

于 2014-09-11T04:55:03.790 に答える