From 6ba5b1302e79ba255f157d116053cd3fa2229235 Mon Sep 17 00:00:00 2001 From: fly_mc Date: Sun, 29 Sep 2024 01:07:46 +0800 Subject: [PATCH] use PGroonga --- .../migration/1652210810723-PGroonga.js | 11 ++++ .../1652213168020-PGroongaUserName.js | 11 ++++ .../1652213556290-PGroongaUserDescription.js | 11 ++++ .../migration/1727542814489-Pgroonga.js | 16 ++++++ packages/backend/src/core/SearchService.ts | 2 +- packages/backend/src/models/Note.ts | 1 + packages/backend/src/models/User.ts | 1 + packages/backend/src/models/UserProfile.ts | 1 + .../src/server/api/endpoints/notes/search.ts | 6 +++ .../src/server/api/endpoints/users/search.ts | 8 +-- pgroonga.diff | 51 +++++++++++++++++++ 11 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 packages/backend/migration/1652210810723-PGroonga.js create mode 100644 packages/backend/migration/1652213168020-PGroongaUserName.js create mode 100644 packages/backend/migration/1652213556290-PGroongaUserDescription.js create mode 100644 packages/backend/migration/1727542814489-Pgroonga.js create mode 100644 pgroonga.diff diff --git a/packages/backend/migration/1652210810723-PGroonga.js b/packages/backend/migration/1652210810723-PGroonga.js new file mode 100644 index 000000000..bd3fee34e --- /dev/null +++ b/packages/backend/migration/1652210810723-PGroonga.js @@ -0,0 +1,11 @@ +export class PGroonga1652210810723 { + name = 'PGroonga1652210810723' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_f27f5d88941e57442be75ba9c8" ON "note" USING "pgroonga" ("text")`); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_f27f5d88941e57442be75ba9c8"`); + } +} diff --git a/packages/backend/migration/1652213168020-PGroongaUserName.js b/packages/backend/migration/1652213168020-PGroongaUserName.js new file mode 100644 index 000000000..9e1e75ece --- /dev/null +++ b/packages/backend/migration/1652213168020-PGroongaUserName.js @@ -0,0 +1,11 @@ +export class PGroongaUserName1652213168020 { + name = 'PGroongaUserName1652213168020' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_065d4d8f3b5adb4a08841eae3c" ON "user" USING "pgroonga" ("name" pgroonga_varchar_full_text_search_ops_v2)`); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_065d4d8f3b5adb4a08841eae3c"`); + } +} diff --git a/packages/backend/migration/1652213556290-PGroongaUserDescription.js b/packages/backend/migration/1652213556290-PGroongaUserDescription.js new file mode 100644 index 000000000..7216438ab --- /dev/null +++ b/packages/backend/migration/1652213556290-PGroongaUserDescription.js @@ -0,0 +1,11 @@ +export class PGroongaUserDescription1652213556290 { + name = 'PGroongaUserDescription1652213556290' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_fcb770976ff8240af5799e3ffc" ON "user_profile" USING "pgroonga" ("description" pgroonga_varchar_full_text_search_ops_v2) `); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_fcb770976ff8240af5799e3ffc"`); + } +} diff --git a/packages/backend/migration/1727542814489-Pgroonga.js b/packages/backend/migration/1727542814489-Pgroonga.js new file mode 100644 index 000000000..b8e3e4a46 --- /dev/null +++ b/packages/backend/migration/1727542814489-Pgroonga.js @@ -0,0 +1,16 @@ +export class Pgroonga1727542814489 { + name = 'Pgroonga1727542814489' + + async up(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_f27f5d88941e57442be75ba9c8" ON "note" USING "pgroonga" ("text")`); + await queryRunner.query(`CREATE INDEX "IDX_065d4d8f3b5adb4a08841eae3c" ON "user" USING "pgroonga" ("name" pgroonga_varchar_full_text_search_ops_v2)`); + await queryRunner.query(`CREATE INDEX "IDX_fcb770976ff8240af5799e3ffc" ON "user_profile" USING "pgroonga" ("description" pgroonga_varchar_full_text_search_ops_v2) `); + + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_f27f5d88941e57442be75ba9c8"`); + await queryRunner.query(`DROP INDEX "public"."IDX_065d4d8f3b5adb4a08841eae3c"`); + await queryRunner.query(`DROP INDEX "public"."IDX_fcb770976ff8240af5799e3ffc"`); + } +} \ No newline at end of file diff --git a/packages/backend/src/core/SearchService.ts b/packages/backend/src/core/SearchService.ts index edfc47037..42a32220d 100644 --- a/packages/backend/src/core/SearchService.ts +++ b/packages/backend/src/core/SearchService.ts @@ -215,7 +215,7 @@ export class SearchService { } query - .andWhere('note.text ILIKE :q', { q: `%${ sqlLikeEscape(q) }%` }) + .andWhere('note.text &@~ :q', { q: sqlLikeEscape(q) }) .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts index e7a01960c..87aa7ebb5 100644 --- a/packages/backend/src/models/Note.ts +++ b/packages/backend/src/models/Note.ts @@ -64,6 +64,7 @@ export class MiNote { public threadId: string | null; // TODO: varcharにしたい + @Index() // USING pgroonga @Column('text', { nullable: true, }) diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 9e2d7a344..8fa0d7738 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -49,6 +49,7 @@ export class MiUser { }) public usernameLower: string; + @Index() // USING pgroonga pgroonga_varchar_full_text_search_ops_v2 @Column('varchar', { length: 128, nullable: true, comment: 'The name of the User.', diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 7dbe0b371..93ef7fff8 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -36,6 +36,7 @@ export class MiUserProfile { }) public birthday: string | null; + @Index() // USING pgroonga pgroonga_varchar_full_text_search_ops_v2 @Column('varchar', { length: 2048, nullable: true, comment: 'The description (bio) of the User.', diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index 3fe19806e..a26c49c94 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -31,6 +31,11 @@ export const meta = { code: 'UNAVAILABLE', id: '0b44998d-77aa-4427-80d0-d2c9b8523011', }, + noSuchNote: { + message: 'Query is empty.', + code: 'QUERY_IS_EMPTY', + id: 'd0410b51-f409-4667-8118-cfe999e453c3', + }, }, } as const; @@ -62,6 +67,7 @@ export default class extends Endpoint { // eslint- private roleService: RoleService, ) { super(meta, paramDef, async (ps, me) => { + if (ps.query.trim().length === 0) throw new ApiError(meta.errors.noSuchNote); const policies = await this.roleService.getUserPolicies(me ? me.id : null); if (!policies.canSearchNotes) { throw new ApiError(meta.errors.unavailable); diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 0b0136066..6c686a8eb 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -63,12 +63,12 @@ export default class extends Endpoint { // eslint- const nameQuery = this.usersRepository.createQueryBuilder('user') .where(new Brackets(qb => { - qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' }); + qb.where('user.name &@~ :query', { query: ps.query }); if (isUsername) { qb.orWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' }); - } else if (this.userEntityService.validateLocalUsername(ps.query)) { // Also search username if it qualifies as username - qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' }); + } else if (userEntityService.validateLocalUsername(ps.query)) { // Also search username if it qualifies as username + qb.orWhere('user.usernameLower LIKE :username', { username: ps.query.toLowerCase() + '%' }); } })) .andWhere(new Brackets(qb => { @@ -93,7 +93,7 @@ export default class extends Endpoint { // eslint- if (users.length < ps.limit) { const profQuery = this.userProfilesRepository.createQueryBuilder('prof') .select('prof.userId') - .where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' }); + .where('prof.description &@~ :query', { query: ps.query }); if (ps.origin === 'local') { profQuery.andWhere('prof.userHost IS NULL'); diff --git a/pgroonga.diff b/pgroonga.diff new file mode 100644 index 000000000..c960ba5d9 --- /dev/null +++ b/pgroonga.diff @@ -0,0 +1,51 @@ +diff --git a/packages/backend/migration/1652210810723-PGroonga.js b/packages/backend/migration/1652210810723-PGroonga.js +new file mode 100644 +index 000000000..bd3fee34e +--- /dev/null ++++ b/packages/backend/migration/1652210810723-PGroonga.js +@@ -0,0 +1,11 @@ ++export class PGroonga1652210810723 { ++ name = 'PGroonga1652210810723' ++ ++ async up(queryRunner) { ++ await queryRunner.query(`CREATE INDEX "IDX_f27f5d88941e57442be75ba9c8" ON "note" USING "pgroonga" ("text")`); ++ } ++ ++ async down(queryRunner) { ++ await queryRunner.query(`DROP INDEX "public"."IDX_f27f5d88941e57442be75ba9c8"`); ++ } ++} +diff --git a/packages/backend/migration/1652213168020-PGroongaUserName.js b/packages/backend/migration/1652213168020-PGroongaUserName.js +new file mode 100644 +index 000000000..9e1e75ece +--- /dev/null ++++ b/packages/backend/migration/1652213168020-PGroongaUserName.js +@@ -0,0 +1,11 @@ ++export class PGroongaUserName1652213168020 { ++ name = 'PGroongaUserName1652213168020' ++ ++ async up(queryRunner) { ++ await queryRunner.query(`CREATE INDEX "IDX_065d4d8f3b5adb4a08841eae3c" ON "user" USING "pgroonga" ("name" pgroonga_varchar_full_text_search_ops_v2)`); ++ } ++ ++ async down(queryRunner) { ++ await queryRunner.query(`DROP INDEX "public"."IDX_065d4d8f3b5adb4a08841eae3c"`); ++ } ++} +diff --git a/packages/backend/migration/1652213556290-PGroongaUserDescription.js b/packages/backend/migration/1652213556290-PGroongaUserDescription.js +new file mode 100644 +index 000000000..7216438ab +--- /dev/null ++++ b/packages/backend/migration/1652213556290-PGroongaUserDescription.js +@@ -0,0 +1,11 @@ ++export class PGroongaUserDescription1652213556290 { ++ name = 'PGroongaUserDescription1652213556290' ++ ++ async up(queryRunner) { ++ await queryRunner.query(`CREATE INDEX "IDX_fcb770976ff8240af5799e3ffc" ON "user_profile" USING "pgroonga" ("description" pgroonga_varchar_full_text_search_ops_v2) `); ++ } ++ ++ async down(queryRunner) { ++ await queryRunner.query(`DROP INDEX "public"."IDX_fcb770976ff8240af5799e3ffc"`); ++ } ++}