Configure postgres fts backend

This commit is contained in:
eikek
2022-03-21 11:04:58 +01:00
parent 1e56e832da
commit 21e13341e3
18 changed files with 295 additions and 56 deletions

View File

@ -697,6 +697,9 @@ Docpell Update Check
# Currently the SOLR search platform is supported.
enabled = false
# Which backend to use, either solr or postgresql
backend = "solr"
# Configuration for the SOLR backend.
solr = {
# The URL to solr
@ -713,6 +716,43 @@ Docpell Update Check
q-op = "OR"
}
# Configuration for PostgreSQL backend
postgresql = {
# Whether to use the default database, only works if it is
# postgresql
use-default-connection = false
# The database connection.
jdbc {
url = "jdbc:postgresql://server:5432/db"
user = "pguser"
password = ""
}
# A mapping from a language to a postgres text search config. By
# default a language is mapped to a predefined config.
# PostgreSQL has predefined configs for some languages. This
# setting allows to create a custom text search config and
# define it here for some or all languages.
#
# Example:
# { german = "my-german" }
#
# See https://www.postgresql.org/docs/14/textsearch-tables.html ff.
pg-config = {
}
# Define which query parser to use.
#
# https://www.postgresql.org/docs/14/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
pg-query-parser = "websearch_to_tsquery"
# Allows to define a normalization for the ranking.
#
# https://www.postgresql.org/docs/14/textsearch-controls.html#TEXTSEARCH-RANKING
pg-rank-normalization = [ 4 ]
}
# Settings for running the index migration tasks
migration = {
# Chunk size to use when indexing data from the database. This

View File

@ -13,6 +13,7 @@ import docspell.analysis.TextAnalysisConfig
import docspell.analysis.classifier.TextClassifierConfig
import docspell.backend.Config.Files
import docspell.common._
import docspell.config.{FtsType, PgFtsConfig}
import docspell.convert.ConvertConfig
import docspell.extract.ExtractConfig
import docspell.ftssolr.SolrConfig
@ -65,9 +66,25 @@ object Config {
case class FullTextSearch(
enabled: Boolean,
backend: FtsType,
migration: FullTextSearch.Migration,
solr: SolrConfig
)
solr: SolrConfig,
postgresql: PgFtsConfig
) {
def info: String =
if (!enabled) "Disabled."
else
backend match {
case FtsType.Solr =>
s"Solr(${solr.url.asString})"
case FtsType.PostgreSQL =>
if (postgresql.useDefaultConnection)
"PostgreSQL(default)"
else
s"PostgreSQL(${postgresql.jdbc.url.asString})"
}
}
object FullTextSearch {

View File

@ -9,7 +9,7 @@ package docspell.joex
import cats.effect.Async
import docspell.config.Implicits._
import docspell.config.{ConfigFactory, Validation}
import docspell.config.{ConfigFactory, FtsType, Validation}
import docspell.scheduler.CountingScheme
import emil.MailAddress
@ -53,6 +53,14 @@ object ConfigFile {
cfg => cfg.updateCheck.enabled && cfg.updateCheck.subject.els.isEmpty,
"No subject given for enabled update check!"
),
Validation(cfg => cfg.files.validate.map(_ => cfg))
Validation(cfg => cfg.files.validate.map(_ => cfg)),
Validation.failWhen(
cfg =>
cfg.fullTextSearch.enabled &&
cfg.fullTextSearch.backend == FtsType.PostgreSQL &&
cfg.fullTextSearch.postgresql.useDefaultConnection &&
!cfg.jdbc.dbmsName.contains("postgresql"),
s"PostgreSQL defined fulltext search backend with default-connection, which is not a PostgreSQL connection!"
)
)
}

View File

@ -102,7 +102,8 @@ object JoexAppImpl extends MailAddressCodec {
termSignal: SignallingRef[F, Boolean],
store: Store[F],
httpClient: Client[F],
pubSub: PubSub[F]
pubSub: PubSub[F],
pools: Pools
): Resource[F, JoexApp[F]] =
for {
joexLogger <- Resource.pure(docspell.logging.getLogger[F](s"joex-${cfg.appId.id}"))
@ -120,6 +121,7 @@ object JoexAppImpl extends MailAddressCodec {
tasks <- JoexTasks.resource(
cfg,
pools,
jobStoreModule,
httpClient,
pubSubT,

View File

@ -52,7 +52,7 @@ object JoexServer {
httpClient
)(Topics.all.map(_.topic))
joexApp <- JoexAppImpl.create[F](cfg, signal, store, httpClient, pubSub)
joexApp <- JoexAppImpl.create[F](cfg, signal, store, httpClient, pubSub, pools)
httpApp = Router(
"/internal" -> InternalHeader(settings.internalRouteKey) {

View File

@ -12,8 +12,10 @@ import docspell.analysis.TextAnalyser
import docspell.backend.fulltext.CreateIndex
import docspell.backend.ops._
import docspell.common._
import docspell.config.FtsType
import docspell.ftsclient.FtsClient
import docspell.ftspsql.{PsqlConfig, PsqlFtsClient}
import docspell.ftspsql.PsqlFtsClient
import docspell.ftssolr.SolrFtsClient
import docspell.joex.analysis.RegexNerFile
import docspell.joex.emptytrash.EmptyTrashTask
import docspell.joex.filecopy.{FileCopyTask, FileIntegrityCheckTask}
@ -211,6 +213,7 @@ object JoexTasks {
def resource[F[_]: Async](
cfg: Config,
pools: Pools,
jobStoreModule: JobStoreModuleBuilder.Module[F],
httpClient: Client[F],
pubSub: PubSubT[F],
@ -221,7 +224,7 @@ object JoexTasks {
joex <- OJoex(pubSub)
store = jobStoreModule.store
upload <- OUpload(store, jobStoreModule.jobs)
fts <- createFtsClient(cfg, store)
fts <- createFtsClient(cfg, pools, store, httpClient)
createIndex <- CreateIndex.resource(fts, store)
itemOps <- OItem(store, fts, createIndex, jobStoreModule.jobs)
itemSearchOps <- OItemSearch(store)
@ -250,16 +253,23 @@ object JoexTasks {
private def createFtsClient[F[_]: Async](
cfg: Config,
store: Store[F] /*,
client: Client[F] */
pools: Pools,
store: Store[F],
client: Client[F]
): Resource[F, FtsClient[F]] =
// if (cfg.fullTextSearch.enabled) SolrFtsClient(cfg.fullTextSearch.solr, client)
if (cfg.fullTextSearch.enabled)
Resource.pure[F, FtsClient[F]](
new PsqlFtsClient[F](
PsqlConfig.defaults(cfg.jdbc.url, cfg.jdbc.user, Password(cfg.jdbc.password)),
store.transactor
)
)
cfg.fullTextSearch.backend match {
case FtsType.Solr =>
SolrFtsClient(cfg.fullTextSearch.solr, client)
case FtsType.PostgreSQL =>
val psqlCfg = cfg.fullTextSearch.postgresql.toPsqlConfig(cfg.jdbc)
if (cfg.fullTextSearch.postgresql.useDefaultConnection)
Resource.pure[F, FtsClient[F]](
new PsqlFtsClient[F](psqlCfg, store.transactor)
)
else
PsqlFtsClient(psqlCfg, pools.connectEC)
}
else Resource.pure[F, FtsClient[F]](FtsClient.none[F])
}

View File

@ -31,7 +31,7 @@ object Main extends IOApp {
Option(System.getProperty("config.file")),
cfg.appId,
cfg.baseUrl,
Some(cfg.fullTextSearch.solr.url).filter(_ => cfg.fullTextSearch.enabled),
Some(cfg.fullTextSearch.info).filter(_ => cfg.fullTextSearch.enabled),
cfg.files.defaultStoreConfig
)
_ <- logger.info(s"\n${banner.render("***>")}")