1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-01 08:31:59 +00:00

fix(server): search duplicates of the same asset type (#9747)

* search by type

* make sql

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Mert 2024-05-26 18:04:23 -04:00 committed by GitHub
parent 50f9b2d44e
commit e7c8501930
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 16 additions and 6 deletions

View file

@ -155,8 +155,9 @@ export interface FaceEmbeddingSearch extends SearchEmbeddingOptions {
export interface AssetDuplicateSearch { export interface AssetDuplicateSearch {
assetId: string; assetId: string;
embedding: Embedding; embedding: Embedding;
userIds: string[];
maxDistance?: number; maxDistance?: number;
type: AssetType;
userIds: string[];
} }
export interface FaceSearchResult { export interface FaceSearchResult {

View file

@ -204,6 +204,7 @@ WITH
"asset"."ownerId" IN ($2) "asset"."ownerId" IN ($2)
AND "asset"."id" != $3 AND "asset"."id" != $3
AND "asset"."isVisible" = $4 AND "asset"."isVisible" = $4
AND "asset"."type" = $5
) )
AND ("asset"."deletedAt" IS NULL) AND ("asset"."deletedAt" IS NULL)
ORDER BY ORDER BY
@ -216,7 +217,7 @@ SELECT
FROM FROM
"cte" "res" "cte" "res"
WHERE WHERE
res.distance <= $5 res.distance <= $6
-- SearchRepository.searchFaces -- SearchRepository.searchFaces
START TRANSACTION START TRANSACTION

View file

@ -160,6 +160,7 @@ export class SearchRepository implements ISearchRepository {
assetId, assetId,
embedding, embedding,
maxDistance, maxDistance,
type,
userIds, userIds,
}: AssetDuplicateSearch): Promise<AssetDuplicateResult[]> { }: AssetDuplicateSearch): Promise<AssetDuplicateResult[]> {
const cte = this.assetRepository.createQueryBuilder('asset'); const cte = this.assetRepository.createQueryBuilder('asset');
@ -171,18 +172,22 @@ export class SearchRepository implements ISearchRepository {
.where('asset.ownerId IN (:...userIds )') .where('asset.ownerId IN (:...userIds )')
.andWhere('asset.id != :assetId') .andWhere('asset.id != :assetId')
.andWhere('asset.isVisible = :isVisible') .andWhere('asset.isVisible = :isVisible')
.andWhere('asset.type = :type')
.orderBy('search.embedding <=> :embedding') .orderBy('search.embedding <=> :embedding')
.limit(64) .limit(64)
.setParameters({ assetId, embedding: asVector(embedding), isVisible: true, userIds }); .setParameters({ assetId, embedding: asVector(embedding), isVisible: true, type, userIds });
const builder = this.assetRepository.manager const builder = this.assetRepository.manager
.createQueryBuilder() .createQueryBuilder()
.addCommonTableExpression(cte, 'cte') .addCommonTableExpression(cte, 'cte')
.from('cte', 'res') .from('cte', 'res')
.select('res.*') .select('res.*');
.where('res.distance <= :maxDistance', { maxDistance });
return builder.getRawMany() as any as Promise<AssetDuplicateResult[]>; if (maxDistance) {
builder.where('res.distance <= :maxDistance', { maxDistance });
}
return builder.getRawMany() as Promise<AssetDuplicateResult[]>;
} }
@GenerateSql({ @GenerateSql({

View file

@ -215,6 +215,7 @@ describe(SearchService.name, () => {
assetId: assetStub.hasEmbedding.id, assetId: assetStub.hasEmbedding.id,
embedding: assetStub.hasEmbedding.smartSearch!.embedding, embedding: assetStub.hasEmbedding.smartSearch!.embedding,
maxDistance: 0.03, maxDistance: 0.03,
type: assetStub.hasEmbedding.type,
userIds: [assetStub.hasEmbedding.ownerId], userIds: [assetStub.hasEmbedding.ownerId],
}); });
expect(assetMock.updateDuplicates).toHaveBeenCalledWith({ expect(assetMock.updateDuplicates).toHaveBeenCalledWith({
@ -240,6 +241,7 @@ describe(SearchService.name, () => {
assetId: assetStub.hasEmbedding.id, assetId: assetStub.hasEmbedding.id,
embedding: assetStub.hasEmbedding.smartSearch!.embedding, embedding: assetStub.hasEmbedding.smartSearch!.embedding,
maxDistance: 0.03, maxDistance: 0.03,
type: assetStub.hasEmbedding.type,
userIds: [assetStub.hasEmbedding.ownerId], userIds: [assetStub.hasEmbedding.ownerId],
}); });
expect(assetMock.updateDuplicates).toHaveBeenCalledWith({ expect(assetMock.updateDuplicates).toHaveBeenCalledWith({

View file

@ -94,6 +94,7 @@ export class DuplicateService {
assetId: asset.id, assetId: asset.id,
embedding: asset.smartSearch.embedding, embedding: asset.smartSearch.embedding,
maxDistance: machineLearning.duplicateDetection.maxDistance, maxDistance: machineLearning.duplicateDetection.maxDistance,
type: asset.type,
userIds: [asset.ownerId], userIds: [asset.ownerId],
}); });