From 8c1b395f4d01b782af25a9e7a3221e8ee6b9495e Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Mon, 25 May 2026 11:56:23 +0100 Subject: [PATCH 1/3] chore: optimize memberToMerge query Signed-off-by: Joana Maia --- .../database/repositories/memberRepository.ts | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/backend/src/database/repositories/memberRepository.ts b/backend/src/database/repositories/memberRepository.ts index eea1e54379..8af6b70ed4 100644 --- a/backend/src/database/repositories/memberRepository.ts +++ b/backend/src/database/repositories/memberRepository.ts @@ -253,18 +253,15 @@ class MemberRepository { const totalCount = await options.database.sequelize.query( ` + WITH segment_members AS ( + SELECT DISTINCT "memberId" FROM "memberSegmentsAgg" WHERE "segmentId" IN (:segmentIds) + ) SELECT COUNT(*) AS count FROM "memberToMerge" mtm ${membersJoin} - WHERE EXISTS ( - SELECT 1 FROM "memberSegmentsAgg" ms - WHERE ms."memberId" = mtm."memberId" AND ms."segmentId" IN (:segmentIds) - ) - AND EXISTS ( - SELECT 1 FROM "memberSegmentsAgg" ms2 - WHERE ms2."memberId" = mtm."toMergeId" AND ms2."segmentId" IN (:segmentIds) - ) + WHERE mtm."memberId" IN (SELECT "memberId" FROM segment_members) + AND mtm."toMergeId" IN (SELECT "memberId" FROM segment_members) ${memberFilter} ${similarityFilter} ${displayNameFilter} @@ -364,6 +361,9 @@ class MemberRepository { const mems = await options.database.sequelize.query( ` + WITH segment_members AS ( + SELECT DISTINCT "memberId" FROM "memberSegmentsAgg" WHERE "segmentId" IN (:segmentIds) + ) SELECT mtm."memberId" AS id, mtm."toMergeId", @@ -376,14 +376,8 @@ class MemberRepository { FROM "memberToMerge" mtm JOIN members m ON m.id = mtm."memberId" JOIN members m2 ON m2.id = mtm."toMergeId" - WHERE EXISTS ( - SELECT 1 FROM "memberSegmentsAgg" ms - WHERE ms."memberId" = mtm."memberId" AND ms."segmentId" IN (:segmentIds) - ) - AND EXISTS ( - SELECT 1 FROM "memberSegmentsAgg" ms2 - WHERE ms2."memberId" = mtm."toMergeId" AND ms2."segmentId" IN (:segmentIds) - ) + WHERE mtm."memberId" IN (SELECT "memberId" FROM segment_members) + AND mtm."toMergeId" IN (SELECT "memberId" FROM segment_members) AND mtm.similarity IS NOT NULL ${memberFilter} ${similarityFilter} From c08636f2956923ebfec8cdb73536eea6f587ede5 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Mon, 25 May 2026 13:35:47 +0100 Subject: [PATCH 2/3] chore: cap memberToMerge lookup Signed-off-by: Joana Maia --- .../database/repositories/memberRepository.ts | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/backend/src/database/repositories/memberRepository.ts b/backend/src/database/repositories/memberRepository.ts index 8af6b70ed4..60282c3bce 100644 --- a/backend/src/database/repositories/memberRepository.ts +++ b/backend/src/database/repositories/memberRepository.ts @@ -253,15 +253,25 @@ class MemberRepository { const totalCount = await options.database.sequelize.query( ` - WITH segment_members AS ( - SELECT DISTINCT "memberId" FROM "memberSegmentsAgg" WHERE "segmentId" IN (:segmentIds) + WITH top_candidates AS ( + SELECT "memberId", "toMergeId", similarity, "activityEstimate" + FROM "memberToMerge" + WHERE similarity IS NOT NULL + ORDER BY similarity DESC, "activityEstimate" DESC + LIMIT 5000 ) SELECT COUNT(*) AS count - FROM "memberToMerge" mtm + FROM top_candidates mtm ${membersJoin} - WHERE mtm."memberId" IN (SELECT "memberId" FROM segment_members) - AND mtm."toMergeId" IN (SELECT "memberId" FROM segment_members) + WHERE EXISTS ( + SELECT 1 FROM "memberSegmentsAgg" ms + WHERE ms."memberId" = mtm."memberId" AND ms."segmentId" IN (:segmentIds) + ) + AND EXISTS ( + SELECT 1 FROM "memberSegmentsAgg" ms2 + WHERE ms2."memberId" = mtm."toMergeId" AND ms2."segmentId" IN (:segmentIds) + ) ${memberFilter} ${similarityFilter} ${displayNameFilter} @@ -361,8 +371,12 @@ class MemberRepository { const mems = await options.database.sequelize.query( ` - WITH segment_members AS ( - SELECT DISTINCT "memberId" FROM "memberSegmentsAgg" WHERE "segmentId" IN (:segmentIds) + WITH top_candidates AS ( + SELECT "memberId", "toMergeId", similarity, "activityEstimate" + FROM "memberToMerge" + WHERE similarity IS NOT NULL + ORDER BY similarity DESC, "activityEstimate" DESC + LIMIT 5000 ) SELECT mtm."memberId" AS id, @@ -373,12 +387,17 @@ class MemberRepository { m.attributes->'avatarUrl'->>'default' as "primaryAvatarUrl", m2."displayName" as "toMergeDisplayName", m2.attributes->'avatarUrl'->>'default' as "toMergeAvatarUrl" - FROM "memberToMerge" mtm + FROM top_candidates mtm JOIN members m ON m.id = mtm."memberId" JOIN members m2 ON m2.id = mtm."toMergeId" - WHERE mtm."memberId" IN (SELECT "memberId" FROM segment_members) - AND mtm."toMergeId" IN (SELECT "memberId" FROM segment_members) - AND mtm.similarity IS NOT NULL + WHERE EXISTS ( + SELECT 1 FROM "memberSegmentsAgg" ms + WHERE ms."memberId" = mtm."memberId" AND ms."segmentId" IN (:segmentIds) + ) + AND EXISTS ( + SELECT 1 FROM "memberSegmentsAgg" ms2 + WHERE ms2."memberId" = mtm."toMergeId" AND ms2."segmentId" IN (:segmentIds) + ) ${memberFilter} ${similarityFilter} ${displayNameFilter} From 303c318493847bdfeaca8d5dd4a67466ceb5b174 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Mon, 25 May 2026 14:00:48 +0100 Subject: [PATCH 3/3] chore: allow overriding LLM model in mergeMembersWithLLM workflow Signed-off-by: Joana Maia --- services/apps/merge_suggestions_worker/src/types.ts | 1 + .../src/workflows/mergeMembersWithLLM.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/apps/merge_suggestions_worker/src/types.ts b/services/apps/merge_suggestions_worker/src/types.ts index 167dea0bab..fa1166b17d 100644 --- a/services/apps/merge_suggestions_worker/src/types.ts +++ b/services/apps/merge_suggestions_worker/src/types.ts @@ -104,6 +104,7 @@ export interface IProcessMergeOrganizationSuggestionsWithLLM { export interface IProcessMergeMemberSuggestionsWithLLM { similarity: ISimilarityFilter tenantId: string + modelId?: string } export interface ISimilarMemberOpensearchResult { diff --git a/services/apps/merge_suggestions_worker/src/workflows/mergeMembersWithLLM.ts b/services/apps/merge_suggestions_worker/src/workflows/mergeMembersWithLLM.ts index 03f0af6b1b..e3fa45c0ee 100644 --- a/services/apps/merge_suggestions_worker/src/workflows/mergeMembersWithLLM.ts +++ b/services/apps/merge_suggestions_worker/src/workflows/mergeMembersWithLLM.ts @@ -1,6 +1,6 @@ import { continueAsNew, proxyActivities } from '@temporalio/workflow' -import { LLMSuggestionVerdictType, MemberMergeSuggestionTable } from '@crowd/types' +import { LLMSuggestionVerdictType, LlmModelType, MemberMergeSuggestionTable } from '@crowd/types' import * as commonActivities from '../activities/common' import * as memberActivities from '../activities/memberMergeSuggestions' @@ -24,7 +24,7 @@ export async function mergeMembersWithLLM( ): Promise { const SUGGESTIONS_PER_RUN = 10 const REGION = 'us-east-1' - const MODEL_ID = 'us.anthropic.claude-sonnet-4-20250514-v1:0' + const MODEL_ID = args.modelId ?? LlmModelType.CLAUDE_SONNET_4 const MODEL_ARGS = { max_tokens: 2000, anthropic_version: 'bedrock-2023-05-31',