Improve local search relevancy

pull/6610/head
Chocobozzz 2024-09-12 09:54:37 +02:00
parent f27f392721
commit e18ac0a468
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
4 changed files with 25 additions and 16 deletions

View File

@ -1,8 +1,9 @@
import { isTestOrDevInstance } from '@peertube/peertube-node-utils' import { isTestOrDevInstance } from '@peertube/peertube-node-utils'
import { ActorCustomPageModel } from '@server/models/account/actor-custom-page.js' import { ActorCustomPageModel } from '@server/models/account/actor-custom-page.js'
import { AccountAutomaticTagPolicyModel } from '@server/models/automatic-tag/account-automatic-tag-policy.js'
import { AutomaticTagModel } from '@server/models/automatic-tag/automatic-tag.js' import { AutomaticTagModel } from '@server/models/automatic-tag/automatic-tag.js'
import { VideoAutomaticTagModel } from '@server/models/automatic-tag/video-automatic-tag.js'
import { CommentAutomaticTagModel } from '@server/models/automatic-tag/comment-automatic-tag.js' import { CommentAutomaticTagModel } from '@server/models/automatic-tag/comment-automatic-tag.js'
import { VideoAutomaticTagModel } from '@server/models/automatic-tag/video-automatic-tag.js'
import { RunnerJobModel } from '@server/models/runner/runner-job.js' import { RunnerJobModel } from '@server/models/runner/runner-job.js'
import { RunnerRegistrationTokenModel } from '@server/models/runner/runner-registration-token.js' import { RunnerRegistrationTokenModel } from '@server/models/runner/runner-registration-token.js'
import { RunnerModel } from '@server/models/runner/runner.js' import { RunnerModel } from '@server/models/runner/runner.js'
@ -66,7 +67,6 @@ import { VideoTagModel } from '../models/video/video-tag.js'
import { VideoModel } from '../models/video/video.js' import { VideoModel } from '../models/video/video.js'
import { VideoViewModel } from '../models/view/video-view.js' import { VideoViewModel } from '../models/view/video-view.js'
import { CONFIG } from './config.js' import { CONFIG } from './config.js'
import { AccountAutomaticTagPolicyModel } from '@server/models/automatic-tag/account-automatic-tag-policy.js'
pg.defaults.parseInt8 = true // Avoid BIGINT to be converted to string pg.defaults.parseInt8 = true // Avoid BIGINT to be converted to string
@ -87,7 +87,7 @@ if (CONFIG.DATABASE.SSL) {
} }
} }
const sequelizeTypescript = new SequelizeTypescript({ export const sequelizeTypescript = new SequelizeTypescript({
database: dbname, database: dbname,
dialect: 'postgres', dialect: 'postgres',
dialectOptions, dialectOptions,
@ -112,7 +112,7 @@ const sequelizeTypescript = new SequelizeTypescript({
} }
}) })
function checkDatabaseConnectionOrDie () { export function checkDatabaseConnectionOrDie () {
sequelizeTypescript.authenticate() sequelizeTypescript.authenticate()
.then(() => logger.debug('Connection to PostgreSQL has been established successfully.')) .then(() => logger.debug('Connection to PostgreSQL has been established successfully.'))
.catch(err => { .catch(err => {
@ -122,7 +122,7 @@ function checkDatabaseConnectionOrDie () {
}) })
} }
async function initDatabaseModels (silent: boolean) { export async function initDatabaseModels (silent: boolean) {
sequelizeTypescript.addModels([ sequelizeTypescript.addModels([
ApplicationModel, ApplicationModel,
ActorModel, ActorModel,
@ -192,18 +192,13 @@ async function initDatabaseModels (silent: boolean) {
// Check extensions exist in the database // Check extensions exist in the database
await checkPostgresExtensions() await checkPostgresExtensions()
// Create custom PostgreSQL functions
await createFunctions() await createFunctions()
if (!silent) logger.info('Database %s is ready.', dbname) if (!silent) logger.info('Database %s is ready.', dbname)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Private
export {
checkDatabaseConnectionOrDie, initDatabaseModels, sequelizeTypescript
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
async function checkPostgresExtensions () { async function checkPostgresExtensions () {

View File

@ -10,11 +10,13 @@ export class AbstractRunQuery {
protected query: string protected query: string
protected replacements: any = {} protected replacements: any = {}
protected queryConfig = ''
constructor (protected readonly sequelize: Sequelize) { constructor (protected readonly sequelize: Sequelize) {
} }
protected runQuery (options: { nest?: boolean, transaction?: Transaction, logging?: boolean } = {}) { protected async runQuery (options: { nest?: boolean, transaction?: Transaction, logging?: boolean } = {}) {
const queryOptions = { const queryOptions = {
transaction: options.transaction, transaction: options.transaction,
logging: options.logging, logging: options.logging,
@ -23,6 +25,10 @@ export class AbstractRunQuery {
nest: options.nest ?? false nest: options.nest ?? false
} }
if (this.queryConfig) {
await this.sequelize.query(this.queryConfig, queryOptions)
}
return this.sequelize.query<any>(this.query, queryOptions) return this.sequelize.query<any>(this.query, queryOptions)
} }

View File

@ -127,7 +127,12 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
getQuery (options: BuildVideosListQueryOptions) { getQuery (options: BuildVideosListQueryOptions) {
this.buildIdsListQuery(options) this.buildIdsListQuery(options)
return { query: this.query, sort: this.sort, replacements: this.replacements } return {
query: this.query,
sort: this.sort,
replacements: this.replacements,
queryConfig: this.queryConfig
}
} }
private buildIdsListQuery (options: BuildVideosListQueryOptions) { private buildIdsListQuery (options: BuildVideosListQueryOptions) {
@ -574,12 +579,14 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
const escapedSearch = this.sequelize.escape(search) const escapedSearch = this.sequelize.escape(search)
const escapedLikeSearch = this.sequelize.escape('%' + search + '%') const escapedLikeSearch = this.sequelize.escape('%' + search + '%')
this.queryConfig = 'SET pg_trgm.word_similarity_threshold = 0.40;'
this.cte.push( this.cte.push(
'"trigramSearch" AS (' + '"trigramSearch" AS (' +
' SELECT "video"."id", ' + ' SELECT "video"."id", ' +
` word_similarity(lower(immutable_unaccent("video"."name")), lower(immutable_unaccent(${escapedSearch}))) as similarity ` + ` word_similarity(lower(immutable_unaccent(${escapedSearch})), lower(immutable_unaccent("video"."name"))) as similarity ` +
' FROM "video" ' + ' FROM "video" ' +
' WHERE lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' + ' WHERE lower(immutable_unaccent(' + escapedSearch + ')) <% lower(immutable_unaccent("video"."name")) OR ' +
' lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' + ' lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' +
')' ')'
) )

View File

@ -66,11 +66,12 @@ export class VideosModelListQueryBuilder extends AbstractVideoQueryBuilder {
private buildInnerQuery (options: BuildVideosListQueryOptions) { private buildInnerQuery (options: BuildVideosListQueryOptions) {
const idsQueryBuilder = new VideosIdListQueryBuilder(this.sequelize) const idsQueryBuilder = new VideosIdListQueryBuilder(this.sequelize)
const { query, sort, replacements } = idsQueryBuilder.getQuery(options) const { query, sort, replacements, queryConfig } = idsQueryBuilder.getQuery(options)
this.replacements = replacements this.replacements = replacements
this.innerQuery = query this.innerQuery = query
this.innerSort = sort this.innerSort = sort
this.queryConfig = queryConfig
} }
private buildMainQuery (options: BuildVideosListQueryOptions, serverActor: MActorAccount) { private buildMainQuery (options: BuildVideosListQueryOptions, serverActor: MActorAccount) {