fix slow search resolver without searchTerm input (#9947)

### Issue
Empty searchTerm search resolver 
```
      .orderBy(
        `ts_rank_cd("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`,
        'DESC',
      )
      .addOrderBy(
        `ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTermsOr))`,
        'DESC',
      )
```
builds the following SQL query:
```
ORDER BY
	ts_rank_cd("searchVector", to_tsquery('')) DESC, ts_rank("searchVector", to_tsquery('')) DESC
```

I haven't been able to find doc on this issue, but after testing,
`ts_rank_cd("searchVector", to_tsquery(''))` slows down/freezes my local
db.
As well, ordering by ts_rank is useless without a searchTerm.

### Result
In local, with the imported 300k rows appEvent custom object,
'combinedSearchRecords' gql request with empty searchTerm reduces exec
time from 3s to 300ms.

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
This commit is contained in:
Etienne
2025-01-31 14:26:19 +01:00
committed by GitHub
parent d946cdcba4
commit 2ab88a6cfe

View File

@ -78,34 +78,41 @@ export class GraphqlQuerySearchResolverService extends GraphqlQueryBaseResolverS
const countQueryBuilder = queryBuilder.clone(); const countQueryBuilder = queryBuilder.clone();
const resultsWithTsVector = (await queryBuilder const resultsQueryBuilder =
.andWhere( searchTerms !== ''
new Brackets((qb) => { ? queryBuilder
qb.where( .andWhere(
searchTerms === '' new Brackets((qb) => {
? `"${SEARCH_VECTOR_FIELD.name}" IS NOT NULL` qb.where(
: `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery('simple', :searchTerms)`, `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery('simple', :searchTerms)`,
searchTerms === '' ? {} : { searchTerms }, { searchTerms },
).orWhere( ).orWhere(
searchTermsOr === '' `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery('simple', :searchTermsOr)`,
? `"${SEARCH_VECTOR_FIELD.name}" IS NOT NULL` { searchTermsOr },
: `"${SEARCH_VECTOR_FIELD.name}" @@ to_tsquery('simple', :searchTermsOr)`, );
searchTermsOr === '' ? {} : { searchTermsOr }, }),
); )
}), .orderBy(
) `ts_rank_cd("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`,
.orderBy( 'DESC',
`ts_rank_cd("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTerms))`, )
'DESC', .addOrderBy(
) `ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTermsOr))`,
.addOrderBy( 'DESC',
`ts_rank("${SEARCH_VECTOR_FIELD.name}", to_tsquery(:searchTermsOr))`, )
'DESC', .setParameter('searchTerms', searchTerms)
) .setParameter('searchTermsOr', searchTermsOr)
.setParameter('searchTerms', searchTerms) .take(limit)
.setParameter('searchTermsOr', searchTermsOr) : queryBuilder
.take(limit) .andWhere(
.getMany()) as ObjectRecord[]; new Brackets((qb) => {
qb.where(`"${SEARCH_VECTOR_FIELD.name}" IS NOT NULL`);
}),
)
.take(limit);
const resultsWithTsVector =
(await resultsQueryBuilder.getMany()) as ObjectRecord[];
const objectRecords = formatResult<ObjectRecord[]>( const objectRecords = formatResult<ObjectRecord[]>(
resultsWithTsVector, resultsWithTsVector,