From 6e6db8a443f10ed74f1320de9658cef072f5d4e9 Mon Sep 17 00:00:00 2001 From: "Vink, S.A. (Sjoerd)" <s.a.vink@uu.nl> Date: Fri, 12 Jul 2024 15:20:13 +0200 Subject: [PATCH] feat(schema-attribute-info): statistics for schema attributes --- libs/shared/lib/data-access/api/eventBus.tsx | 9 ++- .../lib/data-access/store/schemaSlice.ts | 15 +++- .../querybuilder/model/graphology/utils.ts | 4 +- libs/shared/lib/schema/model/FromBackend.ts | 78 ++++++++++++++++++- .../lib/schema/schema-utils/schema-utils.ts | 36 ++++++++- 5 files changed, 135 insertions(+), 7 deletions(-) diff --git a/libs/shared/lib/data-access/api/eventBus.tsx b/libs/shared/lib/data-access/api/eventBus.tsx index 3eb73142c..2d9b86d92 100644 --- a/libs/shared/lib/data-access/api/eventBus.tsx +++ b/libs/shared/lib/data-access/api/eventBus.tsx @@ -49,9 +49,10 @@ import { import { URLParams, getParam, deleteParam } from './url'; import { VisState, setVisualizationState } from '../store/visualizationSlice'; import { isEqual } from 'lodash-es'; -import { addSchemaAttributeDimensions } from '../store/schemaSlice'; +import { addSchemaAttributeDimensions, addSchemaAttributeInformation } from '../store/schemaSlice'; import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; import { unSelect } from '../store/interactionSlice'; +import { GraphAttributeStats } from '../../schema'; export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }) => { const { login } = useAuth(); @@ -112,6 +113,11 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } }), ); + Broker.instance().subscribe((data: GraphAttributeStats) => { + dispatch(addSchemaAttributeInformation(data)); + dispatch(addInfo('Received attribute information')); + }, 'schema_stats_result'); + Broker.instance().subscribe((data: any) => { dispatch(addSchemaAttributeDimensions(data)); dispatch(addInfo('Attribute dimensions added')); @@ -176,6 +182,7 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function } unsub(); }); Broker.instance().unSubscribeAll('query_translation_result'); + Broker.instance().unSubscribeAll('schema_stats_result'); Broker.instance().unSubscribeAll('schema_inference'); }; }, []); diff --git a/libs/shared/lib/data-access/store/schemaSlice.ts b/libs/shared/lib/data-access/store/schemaSlice.ts index f31275e6b..b3d4d01f8 100644 --- a/libs/shared/lib/data-access/store/schemaSlice.ts +++ b/libs/shared/lib/data-access/store/schemaSlice.ts @@ -2,7 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { RootState } from './store'; import { AllLayoutAlgorithms, Layouts } from '@graphpolaris/shared/lib/graph-layout'; import { SchemaUtils } from '../../schema/schema-utils'; -import { SchemaFromBackend, SchemaGraph, SchemaGraphology } from '../../schema'; +import { GraphAttributeStats, SchemaFromBackend, SchemaGraph, SchemaGraphology } from '../../schema'; /**************************************************************** */ @@ -52,9 +52,20 @@ export const schemaSlice = createSlice({ addSchemaAttributeDimensions: (state, action: PayloadAction<any>) => { state.graph = SchemaUtils.addAttributeDimensionsToGraph(state.graph, JSON.parse(action.payload)); }, + + addSchemaAttributeInformation: (state, action: PayloadAction<GraphAttributeStats>) => { + state.graph = SchemaUtils.addAttributeInfoToGraph(state.graph, action.payload); + }, }, }); -export const { readInSchemaFromBackend, setSchema, setSchemaSettings, clearSchema, addSchemaAttributeDimensions } = schemaSlice.actions; +export const { + readInSchemaFromBackend, + setSchema, + setSchemaSettings, + clearSchema, + addSchemaAttributeDimensions, + addSchemaAttributeInformation, +} = schemaSlice.actions; export const schemaSettingsState = (state: RootState) => state.schema.settings; diff --git a/libs/shared/lib/querybuilder/model/graphology/utils.ts b/libs/shared/lib/querybuilder/model/graphology/utils.ts index f08865788..7bc9e0578 100644 --- a/libs/shared/lib/querybuilder/model/graphology/utils.ts +++ b/libs/shared/lib/querybuilder/model/graphology/utils.ts @@ -81,7 +81,7 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges handleData: { ...defaultHandleData, attributeName: optAttribute.name, - attributeType: optAttribute.type, + // attributeType: optAttribute.type, attributeDimension: optAttribute.dimension, handleType: Handles.EntityAttribute, }, @@ -97,7 +97,7 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges handleData: { ...defaultHandleData, attributeName: optAttribute.name, - attributeType: optAttribute.type, + // attributeType: optAttribute.type, attributeDimension: optAttribute.dimension, handleType: Handles.RelationAttribute, }, diff --git a/libs/shared/lib/schema/model/FromBackend.ts b/libs/shared/lib/schema/model/FromBackend.ts index 74611465c..278c3f69f 100644 --- a/libs/shared/lib/schema/model/FromBackend.ts +++ b/libs/shared/lib/schema/model/FromBackend.ts @@ -18,7 +18,18 @@ export type SchemaStatsFromBackend = { }[]; }; -export type SchemaAttributeTypes = 'string' | 'float' | 'int' | 'bool' | 'date' | 'time' | 'datetime' | 'duration'; +export type SchemaAttributeTypes = + | 'string' + | 'float' + | 'int' + | 'bool' + | 'boolean' + | 'date' + | 'time' + | 'datetime' + | 'duration' + | 'number' + | 'location'; export type DimensionType = 'categorical' | 'numerical' | 'temporal' | 'spatial'; @@ -27,6 +38,15 @@ export type SchemaAttribute = { name: string; type: SchemaAttributeTypes; dimension?: DimensionType; + uniqueCount?: number; + categoryCounts?: Record<string, number>; + minValue?: number | string; + maxValue?: number | string; + avgValue?: number; + stDevValue?: number; + firstDate?: string; + lastDate?: string; + [id: string]: any; }; /** Node type, consist of a name and a list of attributes */ @@ -36,6 +56,62 @@ export type SchemaNode = { type?: string; }; +export type GraphAttributeStats = { + nodeStats: Array<NodeOrEdgeStats>; + edgeStats: Array<NodeOrEdgeStats>; +}; + +export type NodeOrEdgeStats = { + key: string; + type?: string; + count: number; + attributeStats: Array<AttributeStats>; +}; + +export type AttributeStats = + | BooleanAttributeStats + | StringAttributeStats + | NumberAttributeStats + | DateTimeAttributeStats + | LocationAttributeStats; + +export type CommonAttributeStats = { + name: string; + type: string; +}; + +export type BooleanAttributeStats = CommonAttributeStats & { + type: 'boolean'; + uniqueCount: number; + categoryCounts?: Record<string, number>; +}; + +export type StringAttributeStats = CommonAttributeStats & { + type: 'string'; + uniqueCount: number; + categoryCounts?: Record<string, number>; +}; + +export type NumberAttributeStats = CommonAttributeStats & { + type: 'number'; + minValue: number; + maxValue: number; + avgValue: number; + stDevValue: number; +}; + +export type DateTimeAttributeStats = CommonAttributeStats & { + type: 'datetime'; + firstDate: string; + lastDate: string; +}; + +export type LocationAttributeStats = CommonAttributeStats & { + type: 'location'; + minValue: string; + maxValue: string; +}; + /** Edge type, consist of a name, start point, end point and a list of attributes */ export type SchemaEdge = { name: string; diff --git a/libs/shared/lib/schema/schema-utils/schema-utils.ts b/libs/shared/lib/schema/schema-utils/schema-utils.ts index 6a26bc74d..fc4b47be9 100644 --- a/libs/shared/lib/schema/schema-utils/schema-utils.ts +++ b/libs/shared/lib/schema/schema-utils/schema-utils.ts @@ -1,4 +1,12 @@ -import { DimensionType, GraphAttributeDimensions, SchemaFromBackend, SchemaGraph, SchemaGraphology, SchemaGraphologyNode } from '../model'; +import { + DimensionType, + GraphAttributeDimensions, + GraphAttributeStats, + SchemaFromBackend, + SchemaGraph, + SchemaGraphology, + SchemaGraphologyNode, +} from '../model'; export class SchemaUtils { public static schemaBackend2Graphology(schemaFromBackend: SchemaFromBackend): SchemaGraphology { @@ -72,4 +80,30 @@ export class SchemaUtils { return graph; } + + public static addAttributeInfoToGraph(graph: SchemaGraph, graphStats: GraphAttributeStats): SchemaGraph { + const { nodeStats, edgeStats } = graphStats; + + graph.nodes.forEach((node) => { + const nodeStat = nodeStats.find((stat) => stat.key === node.key); + if (nodeStat && node.attributes?.attributes) { + node.attributes.attributes = node.attributes.attributes.map((attribute) => { + const attrStat = nodeStat.attributeStats.find((stat) => stat.name === attribute.name); + return attrStat ? { ...attribute, ...attrStat } : attribute; + }); + } + }); + + graph.edges.forEach((edge) => { + const edgeStat = edgeStats.find((stat) => stat.type === edge.attributes?.name); + if (edgeStat && edge.attributes?.attributes) { + edge.attributes.attributes = edge.attributes.attributes.map((attribute: any) => { + const attrStat = edgeStat.attributeStats.find((stat) => stat.name === attribute.name); + return attrStat ? { ...attribute, ...attrStat } : attribute; + }); + } + }); + + return graph; + } } -- GitLab