1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

fix(server): search and explore part 2 (#2031)

* explore logging

* chore: regenerate open api

* fix: explore page
This commit is contained in:
Jason Rasmussen 2023-03-20 23:07:22 -04:00 committed by GitHub
parent 6e1d09fc32
commit 25a10784eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 41 deletions

BIN
mobile/openapi/README.md generated

Binary file not shown.

View File

@ -8,7 +8,7 @@ import {
} from '@app/domain';
import { Injectable, Logger } from '@nestjs/common';
import _, { Dictionary } from 'lodash';
import { filter, firstValueFrom, from, map, mergeMap, toArray } from 'rxjs';
import { catchError, filter, firstValueFrom, from, map, mergeMap, of, toArray } from 'rxjs';
import { Client } from 'typesense';
import { CollectionCreateSchema } from 'typesense/lib/Typesense/Collections';
import { DocumentSchema, SearchResponse } from 'typesense/lib/Typesense/Documents';
@ -148,7 +148,7 @@ export class TypesenseRepository implements ISearchRepository {
const common = {
q: '*',
filter_by: `ownerId:${userId}`,
filter_by: this.buildFilterBy('ownerId', userId, true),
per_page: 100,
};
@ -157,8 +157,8 @@ export class TypesenseRepository implements ISearchRepository {
const { facet_counts: facets } = await asset$.search({
...common,
query_by: 'exifInfo.imageName',
facet_by: this.getFacetFieldNames(SearchCollection.ASSETS),
max_facet_values: 50,
facet_by: 'exifInfo.city,smartInfo.objects',
max_facet_values: 12,
});
return firstValueFrom(
@ -166,23 +166,31 @@ export class TypesenseRepository implements ISearchRepository {
mergeMap(
(facet) =>
from(facet.counts).pipe(
mergeMap(
(count) =>
from(
asset$.search({
...common,
query_by: 'exifInfo.imageName',
filter_by: `${facet.field_name}:${count.value}`,
}),
).pipe(
map((result) => ({
value: count.value,
data: result.hits?.[0]?.document as AssetEntity,
})),
filter((item) => !!item.data),
),
5,
),
mergeMap((count) => {
const config = {
...common,
query_by: 'exifInfo.imageName',
filter_by: [
this.buildFilterBy('ownerId', userId, true),
this.buildFilterBy(facet.field_name, count.value, true),
].join(' && '),
per_page: 1,
};
this.logger.verbose(`Explore subquery: "filter_by:${config.filter_by}" (count:${count.count})`);
return from(asset$.search(config)).pipe(
catchError((error: any) => {
this.logger.warn(`Explore subquery error: ${error}`, error?.stack);
return of({ hits: [] });
}),
map((result) => ({
value: count.value,
data: result.hits?.[0]?.document as AssetEntity,
})),
filter((item) => !!item.data),
);
}, 5),
toArray(),
map((items) => ({
fieldName: facet.field_name as string,
@ -208,7 +216,7 @@ export class TypesenseRepository implements ISearchRepository {
await this.client
.collections(schemaMap[collection].name)
.documents()
.delete({ filter_by: `id: [${ids.join(',')}]` });
.delete({ filter_by: this.buildFilterBy('id', ids, true) });
}
async searchAlbums(query: string, filters: SearchFilter): Promise<SearchResult<AlbumEntity>> {
@ -350,18 +358,17 @@ export class TypesenseRepository implements ISearchRepository {
private getAlbumFilters(filters: SearchFilter) {
const { userId } = filters;
const _filters = [`ownerId:${userId}`];
const _filters = [this.buildFilterBy('ownerId', userId, true)];
if (filters.id) {
_filters.push(`id:=${filters.id}`);
_filters.push(this.buildFilterBy('id', filters.id, true));
}
for (const item of albumSchema.fields || []) {
let value = filters[item.name as keyof SearchFilter];
if (Array.isArray(value)) {
value = `[${value.join(',')}]`;
}
const value = filters[item.name as keyof SearchFilter];
if (item.facet && value !== undefined) {
_filters.push(`${item.name}:${value}`);
_filters.push(this.buildFilterBy(item.name, value));
}
}
@ -373,17 +380,17 @@ export class TypesenseRepository implements ISearchRepository {
}
private getAssetFilters(filters: SearchFilter) {
const _filters = [`ownerId:${filters.userId}`];
const { userId } = filters;
const _filters = [this.buildFilterBy('ownerId', userId, true)];
if (filters.id) {
_filters.push(`id:=${filters.id}`);
_filters.push(this.buildFilterBy('id', filters.id, true));
}
for (const item of assetSchema.fields || []) {
let value = filters[item.name as keyof SearchFilter];
if (Array.isArray(value)) {
value = `[${value.join(',')}]`;
}
const value = filters[item.name as keyof SearchFilter];
if (item.facet && value !== undefined) {
_filters.push(`${item.name}:${value}`);
_filters.push(this.buildFilterBy(item.name, value));
}
}
@ -393,4 +400,19 @@ export class TypesenseRepository implements ISearchRepository {
return result;
}
private buildFilterBy(key: string, values: boolean | string | string[], exact?: boolean) {
const token = exact ? ':=' : ':';
const _values = (Array.isArray(values) ? values : [values]).map((value) => {
if (typeof value === 'boolean' || value === 'true' || value === 'false') {
return value;
}
return '`' + value + '`';
});
const value = _values.length > 1 ? `[${_values.join(',')}]` : _values[0];
return `${key}${token}${value}`;
}
}

View File

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.51.0
* The version of the OpenAPI document: 1.51.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.51.0
* The version of the OpenAPI document: 1.51.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.51.0
* The version of the OpenAPI document: 1.51.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.51.0
* The version of the OpenAPI document: 1.51.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.51.0
* The version of the OpenAPI document: 1.51.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).