Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Table of Contents
- [Numeric Aggregation](#aggs-numeric)
- [Nested Aggregation](#aggs-nested)
- [Sub-aggregations](#aggs-sub)
- [Cardinality Count Aggregation](#aggs-cardinality)
- [Filters](#filter)
- [Basic Filter Unit](#filter-unit)
- [Text Search Unit in Filter](#filter-search)
Expand Down Expand Up @@ -765,6 +766,48 @@ Result:
}
```

<a name="aggs-cardinality"></a>

### 6. Cardinality Count Aggregation
By using `_cardinalityCount` keyword, return a cardinality count of a field.

See [Elasticsearch documentation on Cardinality](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html)

> **Note**
> curenntly does not support nested feilds

Example:

```
query ($filter: JSON) {
_aggregation {
subject(filter: $filter) {
submitter_id {
_cardinalityCount(
precision_threshold: 1000 //optional defaults to 3000
)
}
}
}
}
```

Example result:

```
{
"data": {
"_aggregation": {
"subject": {
"submitter_id": {
"_cardinalityCount": 98
}
}
}
}
}
```

<a name="filter"></a>

## Filters
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gen3/guppy",
"version": "0.15.5",
"version": "0.15.7",
"description": "Server that support GraphQL queries on data from elasticsearch",
"main": "src/server/server.js",
"directories": {
Expand Down
5 changes: 5 additions & 0 deletions src/components/ConnectedFilter/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ConnectedFilter extends React.Component {

this.state = {
allFields,
countFields: this.props.extraAggsFieldsCardinalityCount,
initialAggsData: {},
receivedAggsData: {},
accessibility: ENUM_ACCESSIBILITY.ALL,
Expand All @@ -70,6 +71,7 @@ class ConnectedFilter extends React.Component {
this.props.guppyConfig.path,
this.props.guppyConfig.type,
this.state.allFields,
this.state.countFields,
this.state.accessibility,
this.state.filter,
)
Expand Down Expand Up @@ -126,6 +128,7 @@ class ConnectedFilter extends React.Component {
this.props.guppyConfig.path,
this.props.guppyConfig.type,
this.state.allFields,
this.state.countFields,
mergedFilterResults,
this.state.accessibility,
)
Expand Down Expand Up @@ -317,6 +320,7 @@ ConnectedFilter.propTypes = {
})),
}).isRequired,
extraAggsFields: PropTypes.arrayOf(PropTypes.string),
extraAggsFieldsCardinalityCount: PropTypes.arrayOf(PropTypes.string),
guppyConfig: PropTypes.shape({
path: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
Expand Down Expand Up @@ -344,6 +348,7 @@ ConnectedFilter.propTypes = {

ConnectedFilter.defaultProps = {
extraAggsFields: [],
extraAggsFieldsCardinalityCount: [],
onFilterChange: () => {},
onReceiveNewAggsData: () => {},
className: '',
Expand Down
56 changes: 42 additions & 14 deletions src/components/Utils/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,52 @@ const histogramQueryStrForEachField = (field) => {
}`);
};

const queryGuppyForAggs = (path, type, fields, gqlFilter, acc) => {
const cardinalityQueryStrForEachField = (field) => {
const splittedFieldArray = field.split('.');
const splittedField = splittedFieldArray.shift();

if (splittedFieldArray.length === 0) {
return (`
${splittedField} {
_cardinalityCount
}
`);
}
return (`
${splittedField} {
${cardinalityQueryStrForEachField(splittedFieldArray.join('.'))}
}`);
};

const queryGuppyForAggs = (path, type, fields, cardinalityFields = [], gqlFilter, acc) => {
let accessibility = acc;
if (accessibility !== 'all' && accessibility !== 'accessible' && accessibility !== 'unaccessible') {
accessibility = 'all';
}

const query = `query {
_aggregation {
${type} (accessibility: ${accessibility}) {
${fields.map((field) => histogramQueryStrForEachField(field))}
}
}
}`;
const queryBody = { query };
const queryBody = {};
if (gqlFilter) {
const queryWithFilter = `query ($filter: JSON) {
_aggregation {
${type} (filter: $filter, filterSelf: false, accessibility: ${accessibility}) {
${fields.map((field) => histogramQueryStrForEachField(field))}
${fields.map((field) => histogramQueryStrForEachField(field))},
${cardinalityFields.map((field) => cardinalityQueryStrForEachField(field))}
}
}
}`;
queryBody.variables = { filter: gqlFilter };
queryBody.query = queryWithFilter;
} else {
queryBody.query = `query {
_aggregation {
${type} (accessibility: ${accessibility}) {
${fields.map((field) => histogramQueryStrForEachField(field))}
${cardinalityFields.map((field) => cardinalityQueryStrForEachField(field))}
}
}
}`;
}

return fetch(`${path}${graphqlEndpoint}`, {
method: 'POST',
headers: {
Expand Down Expand Up @@ -265,18 +286,25 @@ export const getGQLFilter = (filterObj) => {
};

export const askGuppyAboutAllFieldsAndOptions = (
path, type, fields, accessibility, filter,
path, type, fields, countFields, accessibility, filter,
) => {
const gqlFilter = getGQLFilter(filter);
return queryGuppyForAggs(path, type, fields, gqlFilter, accessibility);
return queryGuppyForAggs(path, type, fields, countFields, gqlFilter, accessibility);
};

// eslint-disable-next-line max-len
export const askGuppyAboutArrayTypes = (path) => queryGuppyForStatus(path).then((res) => res.indices);

export const askGuppyForAggregationData = (path, type, fields, filter, accessibility) => {
export const askGuppyForAggregationData = (
path,
type,
fields,
countFields,
filter,
accessibility,
) => {
const gqlFilter = getGQLFilter(filter);
return queryGuppyForAggs(path, type, fields, gqlFilter, accessibility);
return queryGuppyForAggs(path, type, fields, countFields, gqlFilter, accessibility);
};

export const askGuppyForSubAggregationData = (
Expand Down
8 changes: 6 additions & 2 deletions src/server/__tests__/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('Schema', () => {

const expectedIndividualAggsSchemas = `
type SubjectAggregation {
_totalCount: Int
_totalCount: Int,
gen3_resource_path: HistogramForString,
gender: HistogramForString,
file_count: HistogramForNumber,
Expand All @@ -121,7 +121,7 @@ describe('Schema', () => {
visits:NestedHistogramForVisits
}
type FileAggregation {
_totalCount: Int
_totalCount: Int,
gen3_resource_path: HistogramForString,
file_id: HistogramForString,
file_size: HistogramForNumber,
Expand All @@ -147,12 +147,15 @@ describe('Schema', () => {

const expectedHistogramSchemas = `
type HistogramForString {
_cardinalityCount(precision_threshold:Int=3000): Int,
histogram: [BucketsForNestedStringAgg]
}
type RegularAccessHistogramForString {
_cardinalityCount(precision_threshold:Int=3000): Int,
histogram: [BucketsForNestedStringAgg]
}
type HistogramForNumber {
_cardinalityCount(precision_threshold:Int=3000): Int,
histogram(
rangeStart: Int,
rangeEnd: Int,
Expand All @@ -162,6 +165,7 @@ describe('Schema', () => {
asTextHistogram: [BucketsForNestedStringAgg]
}
type RegularAccessHistogramForNumber {
_cardinalityCount(precision_threshold:Int=3000): Int,
histogram(
rangeStart: Int,
rangeEnd: Int,
Expand Down
10 changes: 5 additions & 5 deletions src/server/es/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ const fromPathToNode = (esInstance, esIndex, path) => {
};

const mergeRangeOperations = (a, b) => {
let merged = Object.assign({}, a, b);
const merged = { ...a, ...b };

Object.keys(merged).forEach(function(key) {
Object.keys(merged).forEach((key) => {
if (typeof merged[key] === 'object' && merged[key] !== null) {
merged[key] = mergeRangeOperations(a[key], b[key]);
}
})
});

return merged;
}
};

const getNumericTextType = (
esInstance,
Expand Down Expand Up @@ -252,7 +252,7 @@ const getFilterObj = (
esInstance, esIndex, filterItem, aggsField, filterSelf, defaultAuthFilter, objPath,
);
if (filterObj) {
if ("range" in filterObj) {
if ('range' in filterObj) {
filterRange.push(filterObj);
} else {
boolItemsList.push(filterObj);
Expand Down
23 changes: 22 additions & 1 deletion src/server/es/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,32 @@ class ES {
async getCount(esIndex, esType, filter) {
const result = await this.filterData(
{ esInstance: this, esIndex, esType },
{ filter, fields: false, size: 0},
{ filter, fields: false, size: 0 },
);
return result.hits.total;
}

// eslint-disable-next-line camelcase
async getCardinalityCount(esIndex, esType, filter, field, precision_threshold) {
const queryBody = {
size: 0,
aggs: {
cardinality_count: {
cardinality: {
field,
precision_threshold,
},
},
},
};
if (typeof filter !== 'undefined') {
queryBody.query = getFilterObj(this, esIndex, filter);
}

const result = await this.query(esIndex, esType, queryBody);
return result.aggregations.cardinality_count.value;
}

async getData({
esIndex, esType, fields, filter, sort, offset, size,
}) {
Expand Down
30 changes: 30 additions & 0 deletions src/server/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ const textHistogramResolver = async (parent, args, context) => {
});
};

/**
* This resolver is for Cardinality.
* It inherits arguments from its parent,
* and uses "field" from parent and args "precision_threshold" to get the cardinality count
* @param {object} parent
* @param {object} args
*/
const cardinalityResolver = async (parent, args) => {
log.debug('[resolver.cardinalityResolver] args', args);
log.debug('[resolver.cardinalityResolver] parent', parent);
// TODO make work with nested
const {
esInstance, esIndex, esType, filter, field,
} = parent;

// eslint-disable-next-line camelcase
const { precision_threshold } = args;

return esInstance.getCardinalityCount(esIndex, esType, filter, field, precision_threshold);
};

const getFieldAggregationResolverMappingsByField = (field) => {
let isNumericField = false;
if (esFieldNumericTextTypeMapping[field.type] === NumericTextTypeTypeEnum.ES_NUMERIC_TYPE) {
Expand All @@ -137,6 +158,8 @@ const getFieldAggregationResolverMappingsByField = (field) => {
}));
};

// this spreads all fields out into individual resolvers and
// adds "field", "isNumericField" and "nestedPath", to parent
const getFieldAggregationResolverMappings = (esInstance, esIndex) => {
const { fields } = esInstance.getESFields(esIndex);
const fieldAggregationResolverMappings = {};
Expand Down Expand Up @@ -165,6 +188,9 @@ const getFieldAggregationResolverMappings = (esInstance, esIndex) => {
* }
* }
* file_count {
* _cardinality (
* precision_threshold: 1000 //optional
* ), ---> `cardinalityResolver`
* histogram (rangeStart: xx, rangeEnd: xx, rangeStep: xx, binCount: xx)
* { ---> `numericHistogramResolver`
* key
Expand Down Expand Up @@ -259,17 +285,21 @@ const getResolver = (esConfig, esInstance) => {
...typeAggregationResolvers,
...typeNestedAggregationResolvers,
HistogramForNumber: {
_cardinalityCount: cardinalityResolver,
histogram: numericHistogramResolver,
asTextHistogram: textHistogramResolver,
},
HistogramForString: {
_cardinalityCount: cardinalityResolver,
histogram: textHistogramResolver,
},
RegularAccessHistogramForNumber: {
_cardinalityCount: cardinalityResolver,
histogram: numericHistogramResolver,
asTextHistogram: textHistogramResolver,
},
RegularAccessHistogramForString: {
_cardinalityCount: cardinalityResolver,
histogram: textHistogramResolver,
},
Mapping: {
Expand Down
Loading