mirror of
https://github.com/immich-app/immich.git
synced 2025-06-01 04:36:58 -04:00
parent
9fa2424652
commit
fb18129843
@ -187,4 +187,5 @@ export interface ISearchRepository {
|
|||||||
searchFaces(search: FaceEmbeddingSearch): Promise<FaceSearchResult[]>;
|
searchFaces(search: FaceEmbeddingSearch): Promise<FaceSearchResult[]>;
|
||||||
upsert(smartInfo: Partial<SmartInfoEntity>, embedding?: Embedding): Promise<void>;
|
upsert(smartInfo: Partial<SmartInfoEntity>, embedding?: Embedding): Promise<void>;
|
||||||
searchPlaces(placeName: string): Promise<GeodataPlacesEntity[]>;
|
searchPlaces(placeName: string): Promise<GeodataPlacesEntity[]>;
|
||||||
|
deleteAllSearchEmbeddings(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,7 @@ describe(SmartInfoService.name, () => {
|
|||||||
|
|
||||||
expect(jobMock.queueAll).toHaveBeenCalledWith([{ name: JobName.SMART_SEARCH, data: { id: assetStub.image.id } }]);
|
expect(jobMock.queueAll).toHaveBeenCalledWith([{ name: JobName.SMART_SEARCH, data: { id: assetStub.image.id } }]);
|
||||||
expect(assetMock.getWithout).toHaveBeenCalledWith({ skip: 0, take: 1000 }, WithoutProperty.SMART_SEARCH);
|
expect(assetMock.getWithout).toHaveBeenCalledWith({ skip: 0, take: 1000 }, WithoutProperty.SMART_SEARCH);
|
||||||
|
expect(searchMock.deleteAllSearchEmbeddings).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should queue all the assets', async () => {
|
it('should queue all the assets', async () => {
|
||||||
@ -83,6 +84,7 @@ describe(SmartInfoService.name, () => {
|
|||||||
|
|
||||||
expect(jobMock.queueAll).toHaveBeenCalledWith([{ name: JobName.SMART_SEARCH, data: { id: assetStub.image.id } }]);
|
expect(jobMock.queueAll).toHaveBeenCalledWith([{ name: JobName.SMART_SEARCH, data: { id: assetStub.image.id } }]);
|
||||||
expect(assetMock.getAll).toHaveBeenCalled();
|
expect(assetMock.getAll).toHaveBeenCalled();
|
||||||
|
expect(searchMock.deleteAllSearchEmbeddings).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,6 +50,10 @@ export class SmartInfoService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (force) {
|
||||||
|
await this.repository.deleteAllSearchEmbeddings();
|
||||||
|
}
|
||||||
|
|
||||||
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
|
||||||
return force
|
return force
|
||||||
? this.assetRepository.getAll(pagination)
|
? this.assetRepository.getAll(pagination)
|
||||||
|
@ -40,11 +40,11 @@ export class PersonRepository implements IPersonRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteAll(): Promise<void> {
|
async deleteAll(): Promise<void> {
|
||||||
await this.personRepository.delete({});
|
await this.personRepository.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteAllFaces(): Promise<void> {
|
async deleteAllFaces(): Promise<void> {
|
||||||
await this.assetFaceRepository.delete({});
|
await this.assetFaceRepository.query('TRUNCATE TABLE asset_faces CASCADE');
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllFaces(
|
getAllFaces(
|
||||||
|
@ -229,25 +229,17 @@ export class SearchRepository implements ISearchRepository {
|
|||||||
this.logger.log(`Updating database CLIP dimension size to ${dimSize}.`);
|
this.logger.log(`Updating database CLIP dimension size to ${dimSize}.`);
|
||||||
|
|
||||||
await this.smartSearchRepository.manager.transaction(async (manager) => {
|
await this.smartSearchRepository.manager.transaction(async (manager) => {
|
||||||
await manager.query(`DROP TABLE smart_search`);
|
await manager.clear(SmartSearchEntity);
|
||||||
|
await manager.query(`ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE vector(${dimSize})`);
|
||||||
await manager.query(`
|
|
||||||
CREATE TABLE smart_search (
|
|
||||||
"assetId" uuid PRIMARY KEY REFERENCES assets(id) ON DELETE CASCADE,
|
|
||||||
embedding vector(${dimSize}) NOT NULL )`);
|
|
||||||
|
|
||||||
await manager.query(`
|
|
||||||
CREATE INDEX clip_index ON smart_search
|
|
||||||
USING vectors (embedding vector_cos_ops) WITH (options = $$
|
|
||||||
[indexing.hnsw]
|
|
||||||
m = 16
|
|
||||||
ef_construction = 300
|
|
||||||
$$)`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.log(`Successfully updated database CLIP dimension size from ${curDimSize} to ${dimSize}.`);
|
this.logger.log(`Successfully updated database CLIP dimension size from ${curDimSize} to ${dimSize}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteAllSearchEmbeddings(): Promise<void> {
|
||||||
|
return this.smartSearchRepository.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private async getDimSize(): Promise<number> {
|
private async getDimSize(): Promise<number> {
|
||||||
const res = await this.smartSearchRepository.manager.query(`
|
const res = await this.smartSearchRepository.manager.query(`
|
||||||
SELECT atttypmod as dimsize
|
SELECT atttypmod as dimsize
|
||||||
|
@ -8,5 +8,6 @@ export const newSearchRepositoryMock = (): jest.Mocked<ISearchRepository> => {
|
|||||||
searchFaces: jest.fn(),
|
searchFaces: jest.fn(),
|
||||||
upsert: jest.fn(),
|
upsert: jest.fn(),
|
||||||
searchPlaces: jest.fn(),
|
searchPlaces: jest.fn(),
|
||||||
|
deleteAllSearchEmbeddings: jest.fn(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user