Use no-op fts-client if disabled + push this flag to the webui

This commit is contained in:
Eike Kettner 2020-06-21 21:06:08 +02:00
parent 330fdcdd5b
commit cfe5aa8894
10 changed files with 88 additions and 18 deletions

View File

@ -60,7 +60,8 @@ object OFulltext {
} yield ()
def findItems(q: Query, ftsQ: String, batch: Batch): F[Vector[ListItem]] =
findItemsFts(q, ftsQ, batch, itemSearch.findItems)
findItemsFts(q, ftsQ, batch.first, itemSearch.findItems)
.drop(batch.offset.toLong)
.take(batch.limit.toLong)
.compile
.toVector
@ -70,28 +71,33 @@ object OFulltext {
ftsQ: String,
batch: Batch
): F[Vector[ListItemWithTags]] =
findItemsFts(q, ftsQ, batch, itemSearch.findItemsWithTags)
findItemsFts(q, ftsQ, batch.first, itemSearch.findItemsWithTags)
.drop(batch.offset.toLong)
.take(batch.limit.toLong)
.compile
.toVector
private def findItemsFts[A](
private def findItemsFts[A: ItemId](
q: Query,
ftsQ: String,
batch: Batch,
search: (Query, Batch) => F[Vector[A]]
): Stream[F, A] = {
val fq = FtsQuery(ftsQ, q.collective, Nil, batch.limit, batch.offset)
val sqlResult = search(q, batch)
val fq = FtsQuery(ftsQ, q.collective, Set.empty, batch.limit, batch.offset)
val qres =
for {
items <-
items <- sqlResult
ids = items.map(a => ItemId[A].itemId(a))
ftsQ = fq.copy(items = ids.toSet)
ftsR <-
fts
.search(fq)
.search(ftsQ)
.map(_.results.map(_.itemId))
.map(_.toSet)
sq = q.copy(itemIds = Some(items))
res <- search(sq, batch)
res = items.filter(a => ftsR.contains(ItemId[A].itemId(a)))
} yield res
Stream.eval(qres).flatMap { v =>
@ -100,6 +106,23 @@ object OFulltext {
else results ++ findItemsFts(q, ftsQ, batch.next, search)
}
}
})
trait ItemId[A] {
def itemId(a: A): Ident
}
object ItemId {
def apply[A](implicit ev: ItemId[A]): ItemId[A] = ev
def from[A](f: A => Ident): ItemId[A] =
new ItemId[A] {
def itemId(a: A) = f(a)
}
implicit val listItemId: ItemId[ListItem] =
ItemId.from(_.id)
implicit val listItemWithTagsId: ItemId[ListItemWithTags] =
ItemId.from(_.item.id)
}
}

View File

@ -1,6 +1,9 @@
package docspell.ftsclient
import fs2.Stream
import cats.implicits._
import cats.effect._
import org.log4s.getLogger
import docspell.common._
/** The fts client is the interface for docspell to a fulltext search
@ -90,3 +93,29 @@ trait FtsClient[F[_]] {
def clear(logger: Logger[F], collective: Ident): F[Unit]
}
object FtsClient {
def none[F[_]: Sync] =
new FtsClient[F] {
private[this] val logger = Logger.log4s[F](getLogger)
def initialize: F[Unit] =
logger.info("Full-text search is disabled!")
def search(q: FtsQuery): F[FtsResult] =
logger.warn("Full-text search is disabled!") *> FtsResult.empty.pure[F]
def updateIndex(logger: Logger[F], data: Stream[F, TextData]): F[Unit] =
logger.warn("Full-text search is disabled!")
def indexData(logger: Logger[F], data: Stream[F, TextData]): F[Unit] =
logger.warn("Full-text search is disabled!")
def clearAll(logger: Logger[F]): F[Unit] =
logger.warn("Full-text search is disabled!")
def clear(logger: Logger[F], collective: Ident): F[Unit] =
logger.warn("Full-text search is disabled!")
}
}

View File

@ -13,7 +13,7 @@ import docspell.common._
final case class FtsQuery(
q: String,
collective: Ident,
items: List[Ident],
items: Set[Ident],
limit: Int,
offset: Int
) {

View File

@ -14,6 +14,9 @@ final case class FtsResult(
object FtsResult {
val empty =
FtsResult(Duration.millis(0), 0, 0.0, Map.empty, Nil)
sealed trait MatchData
case class AttachmentData(attachId: Ident) extends MatchData
case object ItemData extends MatchData

View File

@ -39,7 +39,7 @@ object QueryData {
val items = fq.items.map(_.id).mkString(" ")
val collQ = s"""${Field.collectiveId.name}:"${fq.collective.id}""""
val filterQ = fq.items match {
case Nil =>
case s if s.isEmpty =>
collQ
case _ =>
(collQ :: List(s"""${Field.itemId.name}:($items)""")).mkString(" AND ")

View File

@ -3,6 +3,10 @@ package docspell.joex
import cats.implicits._
import cats.effect._
import emil.javamail._
import fs2.concurrent.SignallingRef
import scala.concurrent.ExecutionContext
import org.http4s.client.Client
import org.http4s.client.blaze.BlazeClientBuilder
import docspell.common._
import docspell.backend.ops._
import docspell.joex.hk._
@ -15,10 +19,8 @@ import docspell.joexapi.client.JoexClient
import docspell.store.Store
import docspell.store.queue._
import docspell.store.records.RJobLog
import docspell.ftsclient.FtsClient
import docspell.ftssolr.SolrFtsClient
import fs2.concurrent.SignallingRef
import scala.concurrent.ExecutionContext
import org.http4s.client.blaze.BlazeClientBuilder
final class JoexAppImpl[F[_]: ConcurrentEffect: ContextShift: Timer](
cfg: Config,
@ -78,7 +80,7 @@ object JoexAppImpl {
nodeOps <- ONode(store)
joex <- OJoex(client, store)
upload <- OUpload(store, queue, cfg.files, joex)
fts <- SolrFtsClient(cfg.fullTextSearch.solr, httpClient)
fts <- createFtsClient(cfg)(httpClient)
javaEmil =
JavaMailEmil(blocker, Settings.defaultSettings.copy(debug = cfg.mailDebug))
sch <- SchedulerBuilder(cfg.scheduler, blocker, store)
@ -137,4 +139,10 @@ object JoexAppImpl {
app = new JoexAppImpl(cfg, nodeOps, store, queue, pstore, termSignal, sch, psch)
appR <- Resource.make(app.init.map(_ => app))(_.shutdown)
} yield appR
private def createFtsClient[F[_]: ConcurrentEffect: ContextShift](
cfg: Config
)(client: Client[F]): Resource[F, FtsClient[F]] =
if (cfg.fullTextSearch.enabled) SolrFtsClient(cfg.fullTextSearch.solr, client)
else Resource.pure[F, FtsClient[F]](FtsClient.none[F])
}

View File

@ -39,5 +39,6 @@ object RestAppImpl {
private def createFtsClient[F[_]: ConcurrentEffect: ContextShift](
cfg: Config
)(client: Client[F]): Resource[F, FtsClient[F]] =
SolrFtsClient(cfg.fullTextSearch.solr, client)
if (cfg.fullTextSearch.enabled) SolrFtsClient(cfg.fullTextSearch.solr, client)
else Resource.pure[F, FtsClient[F]](FtsClient.none[F])
}

View File

@ -13,7 +13,8 @@ case class Flags(
baseUrl: LenientUri,
signupMode: SignupConfig.Mode,
docspellAssetPath: String,
integrationEnabled: Boolean
integrationEnabled: Boolean,
fullTextSearchEnabled: Boolean
)
object Flags {
@ -23,7 +24,8 @@ object Flags {
cfg.baseUrl,
cfg.backend.signup.mode,
s"/app/assets/docspell-webapp/${BuildInfo.version}",
cfg.integrationEndpoint.enabled
cfg.integrationEndpoint.enabled,
cfg.fullTextSearch.enabled
)
implicit val jsonEncoder: Encoder[Flags] =

View File

@ -199,6 +199,9 @@ object QItem {
def next: Batch =
Batch(offset + limit, limit)
def first: Batch =
Batch(0, limit)
}
object Batch {

View File

@ -15,6 +15,7 @@ type alias Config =
, signupMode : String
, docspellAssetPath : String
, integrationEnabled : Bool
, fullTextSearchEnabled : Bool
}