mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-05 22:55:58 +00:00
Use no-op fts-client if disabled + push this flag to the webui
This commit is contained in:
parent
330fdcdd5b
commit
cfe5aa8894
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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!")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
) {
|
||||
|
@ -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
|
||||
|
@ -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 ")
|
||||
|
@ -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])
|
||||
}
|
||||
|
@ -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])
|
||||
}
|
||||
|
@ -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] =
|
||||
|
@ -199,6 +199,9 @@ object QItem {
|
||||
|
||||
def next: Batch =
|
||||
Batch(offset + limit, limit)
|
||||
|
||||
def first: Batch =
|
||||
Batch(0, limit)
|
||||
}
|
||||
|
||||
object Batch {
|
||||
|
@ -15,6 +15,7 @@ type alias Config =
|
||||
, signupMode : String
|
||||
, docspellAssetPath : String
|
||||
, integrationEnabled : Bool
|
||||
, fullTextSearchEnabled : Bool
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user