merge: TSVector based search provider (!910)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/910

Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
dakkar 2025-02-20 10:27:18 +00:00
commit 93ffd4611c
3 changed files with 18 additions and 2 deletions

View file

@ -222,6 +222,19 @@ fulltextSearch:
# You need to install pgroonga and configure it as a PostgreSQL extension.
# In addition to the above, you need to create a pgroonga index on the text column of the note table.
# see: https://pgroonga.github.io/tutorial/
# - sqlTsvector
# Use Postgres tsvectors.
# You need to create a generated column and index on the note table to use this, followed by an ANALYZE on the table. Beware, this will take a while to be created and the database will remain locked during this process.
# This also enables advanced search syntax, see documentation of websearch_to_tsquery: https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
# Support for multiple languages is currently rather poor and will be improved once post languages become a feature.
#
# Example to set up tsvectors for an English instance:
# ALTER TABLE note ADD COLUMN tsvector_embedding tsvector GENERATED ALWAYS AS ( to_tsvector('english', COALESCE(text, '') || ' ' || COALESCE(cw, '') || ' ' || COALESCE(name, ''))) STORED;
# CREATE INDEX vector_idx ON note USING GIN (tsvector_embedding);
# ANALYZE note;
#
# Note: You can opt to use a different dictionary for better results if your main instance language is not English.
# To get a list, use "SELECT cfgname FROM pg_ts_config;" and replace 'english' with the desired dictionary name.
# - meilisearch
# Use Meilisearch.
# You need to install Meilisearch and configure.

View file

@ -254,7 +254,7 @@ export type Config = {
};
};
export type FulltextSearchProvider = 'sqlLike' | 'sqlPgroonga' | 'meilisearch';
export type FulltextSearchProvider = 'sqlLike' | 'sqlPgroonga' | 'meilisearch' | 'sqlTsvector';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);

View file

@ -240,7 +240,8 @@ export class SearchService {
): Promise<MiNote[]> {
switch (this.provider) {
case 'sqlLike':
case 'sqlPgroonga': {
case 'sqlPgroonga':
case 'sqlTsvector': {
// ほとんど内容に差がないのでsqlLikeとsqlPgroongaを同じ処理にしている.
// 今後の拡張で差が出る用であれば関数を分ける.
return this.searchNoteByLike(q, me, opts, pagination);
@ -280,6 +281,8 @@ export class SearchService {
if (this.config.fulltextSearch?.provider === 'sqlPgroonga') {
query.andWhere('note.text &@~ :q', { q });
} else if (this.config.fulltextSearch?.provider === 'sqlTsvector') {
query.andWhere('note.tsvector_embedding @@ websearch_to_tsquery(:q)', { q });
} else {
query.andWhere('note.text ILIKE :q', { q: `%${ sqlLikeEscape(q) }%` });
}