mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
feat: extend smart search, match exif-description too
This commit is contained in:
parent
3d61548d7d
commit
cacf818ce5
2 changed files with 41 additions and 7 deletions
|
@ -104,6 +104,10 @@ export interface SearchExifOptions {
|
||||||
state?: string | null;
|
state?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SearchTextOptions {
|
||||||
|
query?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface SearchEmbeddingOptions {
|
export interface SearchEmbeddingOptions {
|
||||||
embedding: number[];
|
embedding: number[];
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
|
@ -140,6 +144,7 @@ export type AssetSearchBuilderOptions = Omit<AssetSearchOptions, 'orderDirection
|
||||||
export type SmartSearchOptions = SearchDateOptions &
|
export type SmartSearchOptions = SearchDateOptions &
|
||||||
SearchEmbeddingOptions &
|
SearchEmbeddingOptions &
|
||||||
SearchExifOptions &
|
SearchExifOptions &
|
||||||
|
SearchTextOptions &
|
||||||
SearchOneToOneRelationOptions &
|
SearchOneToOneRelationOptions &
|
||||||
SearchStatusOptions &
|
SearchStatusOptions &
|
||||||
SearchUserIdOptions &
|
SearchUserIdOptions &
|
||||||
|
|
|
@ -115,6 +115,7 @@ export class SearchRepository implements ISearchRepository {
|
||||||
{
|
{
|
||||||
takenAfter: DummyValue.DATE,
|
takenAfter: DummyValue.DATE,
|
||||||
embedding: Array.from({ length: 512 }, Math.random),
|
embedding: Array.from({ length: 512 }, Math.random),
|
||||||
|
query: "beach vacation",
|
||||||
lensModel: DummyValue.STRING,
|
lensModel: DummyValue.STRING,
|
||||||
withStacked: true,
|
withStacked: true,
|
||||||
isFavorite: true,
|
isFavorite: true,
|
||||||
|
@ -124,23 +125,51 @@ export class SearchRepository implements ISearchRepository {
|
||||||
})
|
})
|
||||||
async searchSmart(
|
async searchSmart(
|
||||||
pagination: SearchPaginationOptions,
|
pagination: SearchPaginationOptions,
|
||||||
{ embedding, userIds, ...options }: SmartSearchOptions,
|
{ embedding, query, userIds, ...options }: SmartSearchOptions,
|
||||||
): Paginated<AssetEntity> {
|
): Paginated<AssetEntity> {
|
||||||
let results: PaginationResult<AssetEntity> = { items: [], hasNextPage: false };
|
let results: PaginationResult<AssetEntity> = { items: [], hasNextPage: false };
|
||||||
|
|
||||||
await this.assetRepository.manager.transaction(async (manager) => {
|
await this.assetRepository.manager.transaction(async (manager) => {
|
||||||
let builder = manager.createQueryBuilder(AssetEntity, 'asset');
|
let builder = manager.createQueryBuilder(AssetEntity, 'asset')
|
||||||
|
.leftJoinAndSelect('asset.exifInfo', 'exif');
|
||||||
builder = searchAssetBuilder(builder, options);
|
builder = searchAssetBuilder(builder, options);
|
||||||
builder
|
builder.andWhere('asset.ownerId IN (:...userIds)');
|
||||||
.innerJoin('asset.smartSearch', 'search')
|
|
||||||
.andWhere('asset.ownerId IN (:...userIds )')
|
const parameters: Record<string, any> = { userIds };
|
||||||
.orderBy('search.embedding <=> :embedding')
|
|
||||||
.setParameters({ userIds, embedding: asVector(embedding) });
|
if (embedding) {
|
||||||
|
builder
|
||||||
|
.innerJoin('asset.smartSearch', 'search')
|
||||||
|
.addSelect('search.embedding <=> :embedding', 'similarity');
|
||||||
|
parameters.embedding = asVector(embedding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
parameters.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query && embedding) {
|
||||||
|
builder.orderBy(`
|
||||||
|
CASE WHEN to_tsvector('english', COALESCE(exif.description, '')) @@ plainto_tsquery('english', :query)
|
||||||
|
THEN
|
||||||
|
ts_rank(
|
||||||
|
to_tsvector('english', COALESCE(exif.description, '')),
|
||||||
|
plainto_tsquery('english', :query)
|
||||||
|
)
|
||||||
|
ELSE 0 END * 0.7 +
|
||||||
|
COALESCE((1 - (search.embedding <=> :embedding)), 0) * 0.3
|
||||||
|
`, 'DESC');
|
||||||
|
} else if (embedding) {
|
||||||
|
builder.orderBy('search.embedding <=> :embedding', 'ASC');
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.setParameters(parameters);
|
||||||
|
|
||||||
const runtimeConfig = this.getRuntimeConfig(pagination.size);
|
const runtimeConfig = this.getRuntimeConfig(pagination.size);
|
||||||
if (runtimeConfig) {
|
if (runtimeConfig) {
|
||||||
await manager.query(runtimeConfig);
|
await manager.query(runtimeConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
results = await paginatedBuilder<AssetEntity>(builder, {
|
results = await paginatedBuilder<AssetEntity>(builder, {
|
||||||
mode: PaginationMode.LIMIT_OFFSET,
|
mode: PaginationMode.LIMIT_OFFSET,
|
||||||
skip: (pagination.page - 1) * pagination.size,
|
skip: (pagination.page - 1) * pagination.size,
|
||||||
|
|
Loading…
Reference in a new issue