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

@ -289,6 +289,9 @@ docspell.server {
# 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
@ -304,6 +307,43 @@ docspell.server {
# The default combiner for tokens. One of {AND, OR}.
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 ]
}
}
# Configuration for the backend.

View File

@ -9,6 +9,7 @@ package docspell.restserver
import docspell.backend.auth.Login
import docspell.backend.{Config => BackendConfig}
import docspell.common._
import docspell.config.{FtsType, PgFtsConfig}
import docspell.ftssolr.SolrConfig
import docspell.logging.LogConfig
import docspell.oidc.ProviderConfig
@ -92,7 +93,26 @@ object Config {
}
}
case class FullTextSearch(enabled: Boolean, solr: SolrConfig)
case class FullTextSearch(
enabled: Boolean,
backend: FtsType,
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

@ -13,7 +13,7 @@ import cats.effect.Async
import docspell.backend.signup.{Config => SignupConfig}
import docspell.config.Implicits._
import docspell.config.{ConfigFactory, Validation}
import docspell.config.{ConfigFactory, FtsType, Validation}
import docspell.oidc.{ProviderConfig, SignatureAlgo}
import docspell.restserver.auth.OpenId
@ -106,4 +106,15 @@ object ConfigFile {
def filesValidate: Validation[Config] =
Validation(cfg => cfg.backend.files.validate.map(_ => cfg))
def postgresFtsValidate: Validation[Config] =
Validation.failWhen(
cfg =>
cfg.fullTextSearch.enabled &&
cfg.fullTextSearch.backend == FtsType.PostgreSQL &&
cfg.fullTextSearch.postgresql.useDefaultConnection &&
!cfg.backend.jdbc.dbmsName.contains("postgresql"),
s"PostgreSQL defined fulltext search backend with default-connection, which is not a PostgreSQL connection!"
)
}

View File

@ -28,7 +28,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.backend.files.defaultStoreConfig
)
_ <- logger.info(s"\n${banner.render("***>")}")

View File

@ -12,9 +12,11 @@ import fs2.concurrent.Topic
import docspell.backend.BackendApp
import docspell.backend.auth.{AuthToken, ShareToken}
import docspell.common.Password
import docspell.common.Pools
import docspell.config.FtsType
import docspell.ftsclient.FtsClient
import docspell.ftspsql.{PsqlConfig, PsqlFtsClient}
import docspell.ftspsql.PsqlFtsClient
import docspell.ftssolr.SolrFtsClient
import docspell.notification.api.NotificationModule
import docspell.notification.impl.NotificationModuleImpl
import docspell.oidc.CodeFlowRoutes
@ -156,6 +158,7 @@ object RestAppImpl {
def create[F[_]: Async](
cfg: Config,
pools: Pools,
store: Store[F],
httpClient: Client[F],
pubSub: PubSub[F],
@ -164,7 +167,7 @@ object RestAppImpl {
val logger = docspell.logging.getLogger[F](s"restserver-${cfg.appId.id}")
for {
ftsClient <- createFtsClient(cfg, store)
ftsClient <- createFtsClient(cfg, pools, store, httpClient)
pubSubT = PubSubT(pubSub, logger)
javaEmil = JavaMailEmil(cfg.backend.mailSettings)
notificationMod <- Resource.eval(
@ -190,20 +193,24 @@ object RestAppImpl {
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.backend.jdbc.url,
cfg.backend.jdbc.user,
Password(cfg.backend.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.backend.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

@ -88,7 +88,7 @@ object RestServer {
store,
httpClient
)(Topics.all.map(_.topic))
restApp <- RestAppImpl.create[F](cfg, store, httpClient, pubSub, wsTopic)
restApp <- RestAppImpl.create[F](cfg, pools, store, httpClient, pubSub, wsTopic)
} yield (restApp, pubSub, setting)
def createHttpApp[F[_]: Async](