Skip to content

Commit

Permalink
Improve search algorithm (#7955)
Browse files Browse the repository at this point in the history
We were previously checking for matching with each search term
independently. Ex searching for "felix malfait" we were searching for
correspondances with "felix" and "malfait".
As a result record A with name "Marie-Claude Mala" and email
"[email protected]" had a biggest search score than record B "Felix
Malfait" with email [email protected] for search "felix ma":
for record A we had 0 match with felix and 3 matches with "ma" ("marie",
"mala", "ma")
for record B we had 1 match with felix and 1 match with "ma" (with
"malfait").

So we want to give more weight to a row that would combine matches with
both terms, considering "felix malfait" altogether.
  • Loading branch information
ijreilly authored Oct 22, 2024
1 parent e767f16 commit f0a2d38
Showing 1 changed file with 19 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { SearchResolverArgs } from 'src/engine/api/graphql/workspace-resolver-bu
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/constants/search-vector-field.constants';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { isDefined } from 'src/utils/is-defined';
Expand All @@ -24,7 +23,6 @@ export class GraphqlQuerySearchResolverService
{
constructor(
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
private readonly featureFlagService: FeatureFlagService,
) {}

async resolve<
Expand Down Expand Up @@ -61,7 +59,8 @@ export class GraphqlQuerySearchResolverService
hasPreviousPage: false,
});
}
const searchTerms = this.formatSearchTerms(args.searchInput);
const searchTerms = this.formatSearchTerms(args.searchInput, 'and');
const searchTermsOr = this.formatSearchTerms(args.searchInput, 'or');

const limit = args?.limit ?? QUERY_MAX_RECORDS;

Expand All @@ -86,11 +85,22 @@ export class GraphqlQuerySearchResolverService
: `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery(:searchTerms)`,
searchTerms === '' ? {} : { searchTerms },
)
.orWhere(
searchTermsOr === ''
? `"${SEARCH_VECTOR_FIELD.name}" IS NOT NULL`
: `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery(:searchTermsOr)`,
searchTermsOr === '' ? {} : { searchTermsOr },
)
.orderBy(
`ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`,
`ts_rank_cd("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`,
'DESC',
)
.addOrderBy(
`ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTermsOr))`,
'DESC',
)
.setParameter('searchTerms', searchTerms)
.setParameter('searchTermsOr', searchTermsOr)
.take(limit)
.getMany()) as ObjectRecord[];

Expand All @@ -110,7 +120,10 @@ export class GraphqlQuerySearchResolverService
});
}

private formatSearchTerms(searchTerm: string) {
private formatSearchTerms(
searchTerm: string,
operator: 'and' | 'or' = 'and',
) {
if (searchTerm === '') {
return '';
}
Expand All @@ -121,7 +134,7 @@ export class GraphqlQuerySearchResolverService
return `${escapedWord}:*`;
});

return formattedWords.join(' | ');
return formattedWords.join(` ${operator === 'and' ? '&' : '|'} `);
}

async validate(
Expand Down

0 comments on commit f0a2d38

Please sign in to comment.