Skip to content

Commit

Permalink
adding solr search action, hooking into routes, almost working
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Simon committed Jul 17, 2012
1 parent 7f1e71b commit 5bdae58
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 8 deletions.
6 changes: 5 additions & 1 deletion collins/app/controllers/Resources.scala
@@ -1,7 +1,7 @@
package controllers

import actions.asset.{CreateAction, FindSimilarAction}
import actions.resources.{FindAction, IntakeStage1Action, IntakeStage2Action, IntakeStage3Action}
import actions.resources.{FindAction, IntakeStage1Action, IntakeStage2Action, IntakeStage3Action, SolrFindAction}

import models._
import views._
Expand All @@ -24,6 +24,10 @@ trait Resources extends Controller {
Redirect(app.routes.Resources.index).flashing("error" -> "Repopulating Solr index in the background. May take a few minutes to complete")
}

def searchSolr(query: String, details: String, page: Int, size: Int, sort: String) =
SolrFindAction(PageParams(page, size, sort), query, new Truthy(details), Permissions.Resources.Find, this)


def displayCreateForm(assetType: String) = SecureAction { implicit req =>
val atype: Option[AssetType.Enum] = try {
Some(AssetType.Enum.withName(assetType))
Expand Down
58 changes: 58 additions & 0 deletions collins/app/controllers/actions/SolrFindAction.scala
@@ -0,0 +1,58 @@
package controllers
package actions
package resources

import asset.{AssetFinderDataHolder, FindAction => AssetFindAction}

import models.{Asset, AssetView, Page, PageParams, Truthy}
import util.SecuritySpecification
import util.plugins.solr._

import play.api.data.Form
import play.api.data.Forms._
import play.api.mvc.Result

case class SolrFindAction (
pageParams: PageParams,
query: String,
details: Truthy,
spec: SecuritySpecification,
handler: SecureController
) extends AssetFindAction(pageParams, spec, handler) with AssetResultsAction {

case class SolrQueryDataHolder(query: CollinsSearchQuery) extends RequestDataHolder

override def validate(): Either[RequestDataHolder, RequestDataHolder] = (new CollinsQueryParser)
.parseQuery(query)
.right
.flatMap{_.typeCheck}
.fold[Either[RequestDataHolder, RequestDataHolder]](
error => Left(RequestDataHolder.error400(error)),
expr => Right(SolrQueryDataHolder(CollinsSearchQuery(expr, pageParams)))
)

override def execute(rd: RequestDataHolder) = rd match {
case SolrQueryDataHolder(query) => {
query.getPage().fold (
error => handleError(RequestDataHolder.error500(error)),
page => handleSuccess(page, details.isTruthy)
)
}
}

override protected def handleWebSuccess(p: Page[AssetView], details: Boolean): Result = {
p.size match {
case 0 =>
Redirect(app.routes.Resources.index).flashing("message" -> AssetMessages.noMatch)
case 1 =>
Status.Redirect(p.items(0).remoteHost.getOrElse("") + app.routes.CookieApi.getAsset(p.items(0).tag))
case n =>
Status.Ok(views.html.asset.list(p)(flash, request))
}
}

override def handleWebError(rd: RequestDataHolder): Option[Result] = Some(
Redirect(app.routes.Resources.index).flashing("error" -> rd.toString)
)

}
37 changes: 30 additions & 7 deletions collins/app/util/Solr.scala
@@ -1,7 +1,7 @@
package util.plugins
package solr

import models.{Asset, AssetFinder, AssetMeta, AssetMetaValue, AssetView, MetaWrapper, PageParams, Truthy}
import models.{Asset, AssetFinder, AssetMeta, AssetMetaValue, AssetView, MetaWrapper, Page, PageParams, Truthy}

import org.apache.solr.client.solrj._
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer
Expand Down Expand Up @@ -324,10 +324,12 @@ trait SolrSimpleExpr extends SolrExpression {
def AND(k: SolrExpression) = SolrAndOp(this :: k :: Nil)
def OR(k: SolrExpression) = SolrOrOp(this :: k :: Nil)

val nonMetaKeys = List("tag", "assetType", "status", "created", "updated", "deleted")

/**
* returns Left(error) or Right(solr_key_name)
*/
def typeCheckValue(key: String, value: SolrSingleValue):Either[String, String] = AssetMeta.findByName(key) match {
def typeCheckValue(key: String, value: SolrSingleValue):Either[String, String] = if (nonMetaKeys contains key) Right(key) else AssetMeta.findByName(key) match {
case Some(meta) => if (meta.valueType == value.valueType) {
Right(key + value.postfix)
} else {
Expand Down Expand Up @@ -376,7 +378,7 @@ case class SolrKeyRange(key: String, low: SolrSingleValue, high: SolrSingleValue
*/
object CollinsQueryDSL {
class CollinsQueryString(val s: String) {
lazy val query: SolrExpression = (new CollinsQueryParser).parseQuery(s)
lazy val query: SolrExpression = (new CollinsQueryParser).parseQuery(s).right.get
}
implicit def str2collins(s: String): CollinsQueryString = new CollinsQueryString(s)
implicit def collins2str(c: CollinsQueryString): String = c.s
Expand All @@ -398,13 +400,13 @@ class CollinsQueryException(m: String) extends PlayException("CQL", m)
*/
class CollinsQueryParser extends JavaTokenParsers {

def parseQuery(input: String) = parse(expr, input) match {
def parseQuery(input: String): Either[String, SolrExpression] = parse(expr, input) match {
case Success(exp, next) => if (next.atEnd) {
exp
Right(exp)
} else {
throw new CollinsQueryException("Unexpected stuff after query at position %s: %s".format(next.pos.toString, next.first))
Left("Unexpected stuff after query at position %s: %s".format(next.pos.toString, next.first))
}
case Failure(wtf, _) => throw new CollinsQueryException("Error parsing query: %s".format(wtf.toString))
case Failure(wtf, _) => Left("Error parsing query: %s".format(wtf.toString))
}

def expr: Parser[SolrExpression] = orOp
Expand All @@ -427,4 +429,25 @@ class CollinsQueryParser extends JavaTokenParsers {

}

/**
* Note - eventually this can hold faceting information and other metadata
*/
case class CollinsSearchQuery(query: SolrExpression, page: PageParams) {

def getResults(): Either[String, (Seq[AssetView], Int)] = Solr.server.map{server =>
val q = new SolrQuery
q.setQuery(query.toSolrQueryString)
q.setStart(page.offset)
q.setRows(page.size)
val response = server.query(q)
Right((response.getResults.toArray.toSeq.map{case doc: SolrInputDocument => Asset.findByTag(doc.getFieldValue("tag").toString)}.flatten, 0))

}.getOrElse(Left("Solr Plugin not initialized!"))



def getPage(): Either[String, Page[AssetView]] = getResults().right.map{case (results, total) =>
Page(results, page.page, page.size, total)
}

}
1 change: 1 addition & 0 deletions collins/conf/routes
Expand Up @@ -36,6 +36,7 @@ POST /login controllers.Application.authenticate
GET /logout controllers.Application.logout

GET /solr app.Resources.populateSolr
GET /solrsearch app.Resources.searchSolr(query: String, details: String ?= "false", page: Int ?=0, size: Int ?=50, sort: String ?= "ASC")

# API

Expand Down

0 comments on commit 5bdae58

Please sign in to comment.