mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 09:03:02 +00:00
fix: make facets work again
This commit is contained in:
committed by
Rainer Killinger
parent
5d6d4b53f0
commit
d917627d58
@@ -13,13 +13,15 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCBackendAggregationConfiguration, SCFacet, SCThingType} from '@openstapps/core';
|
||||
import {AggregationSchema} from './common';
|
||||
|
||||
/**
|
||||
* Provide information on which type (or on all) an aggregation happens
|
||||
*/
|
||||
export type aggregationType = SCThingType | '@all';
|
||||
import {SCBackendAggregationConfiguration, SCFacet} from '@openstapps/core';
|
||||
import {
|
||||
AggregationResponse,
|
||||
AggregationSchema,
|
||||
ESNestedAggregation,
|
||||
isBucketAggregation,
|
||||
isESNestedAggregation,
|
||||
isESTermsFilter, isNestedAggregation,
|
||||
} from './common';
|
||||
|
||||
/**
|
||||
* Builds the aggregation
|
||||
@@ -29,51 +31,40 @@ export function buildAggregations(aggsConfig: SCBackendAggregationConfiguration[
|
||||
|
||||
const result: AggregationSchema = {};
|
||||
|
||||
aggsConfig.forEach((aggregation) => {
|
||||
for (const aggregation of aggsConfig) {
|
||||
if (typeof aggregation.onlyOnTypes !== 'undefined') {
|
||||
for (const type of aggregation.onlyOnTypes) {
|
||||
if (typeof result[type] === 'undefined') {
|
||||
result[type] = {
|
||||
aggs: {},
|
||||
filter: {
|
||||
type: {
|
||||
value: type,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
result[aggregation.fieldName] = {
|
||||
terms: {
|
||||
field: `${aggregation.fieldName}.raw`,
|
||||
size: 1000,
|
||||
},
|
||||
};
|
||||
});
|
||||
(result[type] as ESNestedAggregation).aggs[aggregation.fieldName] = {
|
||||
terms: {
|
||||
field: `${aggregation.fieldName}.keyword`,
|
||||
size: 1000,
|
||||
},
|
||||
};
|
||||
}
|
||||
} else {
|
||||
result[aggregation.fieldName] = {
|
||||
terms: {
|
||||
field: `${aggregation.fieldName}.keyword`,
|
||||
size: 1000,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch aggregation bucket
|
||||
*/
|
||||
interface Bucket {
|
||||
/**
|
||||
* Number of documents in the agregation bucket
|
||||
*/
|
||||
doc_count: number;
|
||||
|
||||
/**
|
||||
* Text representing the documents in the bucket
|
||||
*/
|
||||
key: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch aggregation response
|
||||
*/
|
||||
interface AggregationResponse {
|
||||
[field: string]: {
|
||||
/**
|
||||
* Buckets in an aggregation
|
||||
*/
|
||||
buckets: Bucket[];
|
||||
|
||||
/**
|
||||
* Number of documents in an aggregation
|
||||
*/
|
||||
doc_count?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses elasticsearch aggregations (response from es) to facets for the app
|
||||
* @param aggregationSchema - aggregation-schema for elasticsearch
|
||||
@@ -85,22 +76,52 @@ export function parseAggregations(
|
||||
|
||||
const facets: SCFacet[] = [];
|
||||
|
||||
const aggregationNames = Object.keys(aggregations);
|
||||
// get all names of the types an aggregation is on
|
||||
for (const typeName in aggregationSchema) {
|
||||
if (aggregationSchema.hasOwnProperty(typeName) && aggregations.hasOwnProperty(typeName)) {
|
||||
// the type object from the schema
|
||||
const type = aggregationSchema[typeName];
|
||||
// the "real" type object from the response
|
||||
const realType = aggregations[typeName];
|
||||
|
||||
aggregationNames.forEach((aggregationName) => {
|
||||
const buckets = aggregations[aggregationName].buckets;
|
||||
const facet: SCFacet = {
|
||||
buckets: buckets.map((bucket) => {
|
||||
return {
|
||||
count: bucket.doc_count,
|
||||
key: bucket.key,
|
||||
};
|
||||
}),
|
||||
field: `${aggregationSchema[aggregationName].terms.field}.raw`,
|
||||
};
|
||||
// both conditions must apply, else we have an error somewhere
|
||||
if (isESNestedAggregation(type) && isNestedAggregation(realType)) {
|
||||
for (const fieldName in type.aggs) {
|
||||
if (type.aggs.hasOwnProperty(fieldName) && realType.hasOwnProperty(fieldName)) {
|
||||
// the field object from the schema
|
||||
const field = type.aggs[fieldName];
|
||||
// the "real" field object from the response
|
||||
const realField = realType[fieldName];
|
||||
|
||||
facets.push(facet);
|
||||
});
|
||||
// this should always be true in theory...
|
||||
if (isESTermsFilter(field) && isBucketAggregation(realField)) {
|
||||
facets.push({
|
||||
buckets: realField.buckets.map((bucket) => {
|
||||
return {
|
||||
count: bucket.doc_count,
|
||||
key: bucket.key,
|
||||
};
|
||||
}),
|
||||
field: fieldName,
|
||||
onlyOnType: type.filter.type.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// the last part here means that it is a bucket aggregation
|
||||
} else if (isESTermsFilter(type) && !isNestedAggregation(realType)) {
|
||||
facets.push({
|
||||
buckets: realType.buckets.map((bucket) => {
|
||||
return {
|
||||
count: bucket.doc_count,
|
||||
key: bucket.key,
|
||||
};
|
||||
}),
|
||||
field: typeName,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return facets;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,83 @@ import {SCThingType} from '@openstapps/core';
|
||||
import {SCThing} from '@openstapps/core';
|
||||
import {NameList} from 'elasticsearch';
|
||||
|
||||
/**
|
||||
* An elasticsearch aggregation bucket
|
||||
*/
|
||||
interface Bucket {
|
||||
/**
|
||||
* Number of documents in the agregation bucket
|
||||
*/
|
||||
doc_count: number;
|
||||
|
||||
/**
|
||||
* Text representing the documents in the bucket
|
||||
*/
|
||||
key: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch aggregation response
|
||||
*/
|
||||
export interface AggregationResponse {
|
||||
/**
|
||||
* The individual aggregations
|
||||
*/
|
||||
[field: string]: BucketAggregation | NestedAggregation;
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch bucket aggregation
|
||||
*/
|
||||
export interface BucketAggregation {
|
||||
/**
|
||||
* Buckets in an aggregation
|
||||
*/
|
||||
buckets: Bucket[];
|
||||
|
||||
/**
|
||||
* Number of documents in an aggregation
|
||||
*/
|
||||
doc_count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the type is a BucketAggregation
|
||||
* @param agg the type to check
|
||||
*/
|
||||
export function isBucketAggregation(agg: BucketAggregation | number): agg is BucketAggregation {
|
||||
return typeof agg !== 'number';
|
||||
}
|
||||
|
||||
/**
|
||||
* An aggregation that contains more aggregations nested inside
|
||||
*/
|
||||
export interface NestedAggregation {
|
||||
/**
|
||||
* Number of documents in an aggregation
|
||||
*/
|
||||
doc_count: number;
|
||||
|
||||
/**
|
||||
* Any nested responses
|
||||
*/
|
||||
[name: string]: BucketAggregation | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the type is a NestedAggregation
|
||||
* @param agg the type to check
|
||||
*/
|
||||
export function isNestedAggregation(agg: BucketAggregation | NestedAggregation): agg is NestedAggregation {
|
||||
return typeof (agg as BucketAggregation).buckets === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch bucket aggregation
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-aggregations-bucket.html
|
||||
*/
|
||||
export interface AggregationSchema {
|
||||
[aggregationName: string]: ESTermsFilter;
|
||||
[aggregationName: string]: ESTermsFilter | ESNestedAggregation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,6 +295,46 @@ export interface ESTermsFilter {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the parameter is of type ESTermsFilter
|
||||
* @param agg the value to check
|
||||
*/
|
||||
export function isESTermsFilter(agg: ESTermsFilter | ESNestedAggregation): agg is ESTermsFilter {
|
||||
return typeof (agg as ESTermsFilter).terms !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* For nested aggregations
|
||||
*/
|
||||
export interface ESNestedAggregation {
|
||||
/**
|
||||
* Possible nested Aggregations
|
||||
*/
|
||||
aggs: AggregationSchema;
|
||||
/**
|
||||
* Possible filter for types
|
||||
*/
|
||||
filter: {
|
||||
/**
|
||||
* The type of the object to find
|
||||
*/
|
||||
type: {
|
||||
/**
|
||||
* The name of the type
|
||||
*/
|
||||
value: SCThingType;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the parameter is of type ESTermsFilter
|
||||
* @param agg the value to check
|
||||
*/
|
||||
export function isESNestedAggregation(agg: ESTermsFilter | ESNestedAggregation): agg is ESNestedAggregation {
|
||||
return typeof (agg as ESNestedAggregation).aggs !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* An elasticsearch type filter
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ const templatePath = resolve(dirPath, `template_${coreVersion}.json`);
|
||||
const errorPath = resolve(dirPath, `failed_template_${coreVersion}.json`);
|
||||
const errorReportPath = resolve(dirPath, `error_report_${coreVersion}.txt`);
|
||||
|
||||
const ignoredTags = ['minlength', 'pattern', 'see'];
|
||||
const ignoredTags = ['minlength', 'pattern', 'see', 'tjs-format']; // TODO: put this into config
|
||||
|
||||
/**
|
||||
* Check if the correct template exists
|
||||
|
||||
Reference in New Issue
Block a user