Skip to content

Commit

Permalink
Merge pull request #211 from swisstopo/feature/assets-205-make-filter…
Browse files Browse the repository at this point in the history
…-interactive

Feature/assets 205 make filter interactive
  • Loading branch information
vej-ananas authored Jul 15, 2024
2 parents b563901 + 6e0996f commit 55af2b9
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,21 +197,7 @@ export class AssetSearchService {
* @param query The query to match with.
*/
async aggregate(query: AssetSearchQuery): Promise<AssetSearchStats> {
const [mapping, _total] = await this.searchAssetsByQuery(query);
const stats = await this.aggregateAssetIds([...mapping.keys()]);
if (stats !== null) {
return stats;
}
return {
total: 0,
assetKindItemCodes: [],
authorIds: [],
createDate: null,
languageItemCodes: [],
geometryCodes: [],
manCatLabelItemCodes: [],
usageCodes: [],
};
return await this.aggregateAssetIds(query);
}

/**
Expand Down Expand Up @@ -320,64 +306,104 @@ export class AssetSearchService {
}
}

private async aggregateAssetIds(assetIds: AssetId[]): Promise<AssetSearchStats | null> {
if (assetIds.length === 0) {
return null;
}

private async aggregateAssetIds(query: AssetSearchQuery): Promise<AssetSearchStats> {
interface Result {
aggregations: {
minCreateDate: { value: DateId };
maxCreateDate: { value: DateId };
authorIds: {
buckets: AggregationBucket<number>[];
};
assetKindItemCodes: {
buckets: AggregationBucket[];
};
languageItemCodes: {
buckets: AggregationBucket[];
};
geometryCodes: {
buckets: AggregationBucket<GeometryCode | 'None'>[];
};
usageCodes: {
buckets: AggregationBucket<UsageCode>[];
};
manCatLabelItemCodes: {
buckets: AggregationBucket[];
};
minCreateDate: { value: DateId };
maxCreateDate: { value: DateId };
authorIds: {
buckets: AggregationBucket<number>[];
};
assetKindItemCodes: {
buckets: AggregationBucket[];
};
languageItemCodes: {
buckets: AggregationBucket[];
};
geometryCodes: {
buckets: AggregationBucket<GeometryCode | 'None'>[];
};
usageCodes: {
buckets: AggregationBucket<UsageCode>[];
};
manCatLabelItemCodes: {
buckets: AggregationBucket[];
};
}

const defaultResult = () =>
({
total: 0,
assetKindItemCodes: [],
authorIds: [],
createDate: null,
languageItemCodes: [],
geometryCodes: [],
manCatLabelItemCodes: [],
usageCodes: [],
} as AssetSearchStats);

interface AggregationBucket<K = string> {
key: K;
doc_count: number;
}

const aggregateGroup = async (query: AssetSearchQuery, operator: string, groupName: string, fieldName?: string) => {
const elasticDslQuery = mapQueryToElasticDsl({ ...query, [groupName]: undefined });
return (
await this.elastic.search({
index: INDEX,
size: 0,
query: elasticDslQuery,
track_total_hits: true,
aggs: {
agg: { [operator]: { field: fieldName ?? groupName } },
},
})
).aggregations?.agg;
};

const elasticQuery = mapQueryToElasticDsl(query);
const response = await this.elastic.search({
index: INDEX,
size: 0,
query: {
terms: {
assetId: assetIds,
},
},
query: elasticQuery,
track_total_hits: true,
aggs: {
authorIds: { terms: { field: 'authorIds' } },
minCreateDate: { min: { field: 'createDate' } },
maxCreateDate: { max: { field: 'createDate' } },
assetKindItemCodes: { terms: { field: 'assetKindItemCode' } },
languageItemCodes: { terms: { field: 'languageItemCodes' } },
geometryCodes: { terms: { field: 'geometryCodes' } },
usageCodes: { terms: { field: 'usageCode' } },
manCatLabelItemCodes: { terms: { field: 'manCatLabelItemCodes' } },
},
});

const total = (response.hits.total as SearchTotalHits).value;
const { aggregations: aggs } = response as unknown as Result;
if (total === 0) {
return defaultResult();
}

const [
assetKindItemCodes,
authorIds,
languageItemCodes,
geometryCodes,
manCatLabelItemCodes,
usageCodes,
minCreateDate,
maxCreateDate,
] = await Promise.all([
aggregateGroup(query, 'terms', 'assetKindItemCodes', 'assetKindItemCode'),
aggregateGroup(query, 'terms', 'authorIds'),
aggregateGroup(query, 'terms', 'languageItemCodes'),
aggregateGroup(query, 'terms', 'geometryCodes'),
aggregateGroup(query, 'terms', 'manCatLabelItemCodes'),
aggregateGroup(query, 'terms', 'usageCodes', 'usageCode'),
aggregateGroup(query, 'min', 'minCreateDate', 'createDate'),
aggregateGroup(query, 'max', 'maxCreateDate', 'createDate'),
]);
const aggs = {
assetKindItemCodes,
authorIds,
languageItemCodes,
geometryCodes,
manCatLabelItemCodes,
usageCodes,
minCreateDate,
maxCreateDate,
} as unknown as Result;

const mapBucket = <T>(bucket: AggregationBucket<T>): ValueCount<T> => ({
value: bucket.key,
count: bucket.doc_count,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<ul>
<li *rxFor="let filter of filters; trackBy: 'value'">
<button [disabled]="filter.count === 0" [class.active]="filter.isActive" (click)="toggle(filter)">
<button
[disabled]="filter.count === 0 && !filter.isActive"
[class.active]="filter.isActive"
(click)="toggle(filter)"
>
{{ filter.name | smartTranslate }} ({{ filter.count }})
</button>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,11 @@ export class AssetSearchEffects {

public updateStats$ = createEffect(() => {
return this.actions$.pipe(
ofType(actions.getStats),
ofType(actions.getStats, actions.search),
withLatestFrom(this.searchStore.select(selectAssetSearchState)),
switchMap(([_, state]) => {
return this.assetSearchService
.updateSearchResultStats({
text: state.query.text,
polygon: state.query.polygon,
})
.updateSearchResultStats(state.query)
.pipe(map((searchStats) => actions.updateStats({ searchStats })));
})
);
Expand Down

0 comments on commit 55af2b9

Please sign in to comment.