mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix(server): search and explore issues (#2029)
* fix: send assets to typesense in batches * fix: run classs transformer on search endpoint * chore: log typesense filters
This commit is contained in:
		@@ -20,7 +20,7 @@ export class SearchController {
 | 
			
		||||
  @Get()
 | 
			
		||||
  async search(
 | 
			
		||||
    @GetAuthUser() authUser: AuthUserDto,
 | 
			
		||||
    @Query(new ValidationPipe({ transform: true })) dto: SearchDto | any,
 | 
			
		||||
    @Query(new ValidationPipe({ transform: true })) dto: SearchDto,
 | 
			
		||||
  ): Promise<SearchResponseDto> {
 | 
			
		||||
    return this.searchService.search(authUser, dto);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -620,7 +620,132 @@
 | 
			
		||||
      "get": {
 | 
			
		||||
        "operationId": "search",
 | 
			
		||||
        "description": "",
 | 
			
		||||
        "parameters": [],
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "q",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "query",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "clip",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "boolean"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "type",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "enum": [
 | 
			
		||||
                "IMAGE",
 | 
			
		||||
                "VIDEO",
 | 
			
		||||
                "AUDIO",
 | 
			
		||||
                "OTHER"
 | 
			
		||||
              ],
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "isFavorite",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "boolean"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "exifInfo.city",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "exifInfo.state",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "exifInfo.country",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "exifInfo.make",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "exifInfo.model",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "string"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "smartInfo.objects",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "array",
 | 
			
		||||
              "items": {
 | 
			
		||||
                "type": "string"
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "smartInfo.tags",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "array",
 | 
			
		||||
              "items": {
 | 
			
		||||
                "type": "string"
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "recent",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "boolean"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "motion",
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "type": "boolean"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": {
 | 
			
		||||
          "200": {
 | 
			
		||||
            "description": "",
 | 
			
		||||
 
 | 
			
		||||
@@ -145,7 +145,15 @@ export class SearchService {
 | 
			
		||||
      // TODO: do this in batches based on searchIndexVersion
 | 
			
		||||
      const assets = this.patchAssets(await this.assetRepository.getAll({ isVisible: true }));
 | 
			
		||||
      this.logger.log(`Indexing ${assets.length} assets`);
 | 
			
		||||
      await this.searchRepository.importAssets(assets, true);
 | 
			
		||||
 | 
			
		||||
      const chunkSize = 1000;
 | 
			
		||||
      for (let i = 0; i < assets.length; i += chunkSize) {
 | 
			
		||||
        const end = i + chunkSize;
 | 
			
		||||
        const chunk = assets.slice(i, end);
 | 
			
		||||
        const done = end >= assets.length - 1;
 | 
			
		||||
        await this.searchRepository.importAssets(chunk, done);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.logger.debug('Finished re-indexing all assets');
 | 
			
		||||
    } catch (error: any) {
 | 
			
		||||
      this.logger.error(`Unable to index all assets`, error?.stack);
 | 
			
		||||
 
 | 
			
		||||
@@ -365,7 +365,11 @@ export class TypesenseRepository implements ISearchRepository {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _filters.join(' && ');
 | 
			
		||||
    const result = _filters.join(' && ');
 | 
			
		||||
 | 
			
		||||
    this.logger.debug(`Album filters are: ${result}`);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getAssetFilters(filters: SearchFilter) {
 | 
			
		||||
@@ -382,6 +386,11 @@ export class TypesenseRepository implements ISearchRepository {
 | 
			
		||||
        _filters.push(`${item.name}:${value}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return _filters.join(' && ');
 | 
			
		||||
 | 
			
		||||
    const result = _filters.join(' && ');
 | 
			
		||||
 | 
			
		||||
    this.logger.debug(`Asset filters are: ${result}`);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user