Delen via


De API voor hiërarchische identiteitfilters in Power BI-visuals

Met de Api voor hiërarchie-identiteitsfilters kunnen visuals die matrixgegevenstoewijzing gebruiken om gegevens op meerdere velden tegelijk te filteren op basis van gegevenspunten die gebruikmaken van een hiërarchiestructuur.

Deze API is handig in de volgende scenario's:

  • Hiërarchieën filteren op basis van gegevenspunten
  • Aangepaste visuals die gebruikmaken van semantische modellen met groep op sleutels

Notitie

De hiërarchieidentiteitsfilter-API is beschikbaar via API-versie 5.9.0

De filterinterface wordt weergegeven in de volgende code:

interface IHierarchyIdentityFilter<IdentityType> extends IFilter {
    target: IHierarchyIdentityFilterTarget;
    hierarchyData: IHierarchyIdentityFilterNode<IdentityType>[];
}
  • $schema: https://powerbi.com/product/schema#hierarchyIdentity (overgenomen van IFilter)

  • filterType: FilterType.HierarchyIdentity (overgenomen van IFilter)

  • doel: Matrix van relevante kolommen in de query. Momenteel wordt slechts één rol ondersteund; Daarom is het doel niet vereist en moet het leeg zijn.

  • hierarchyData: de geselecteerde en niet-geselecteerde items in een hiërarchiestructuur waarin elk IHierarchyIdentityFilterNode<IdentityType> één waardeselectie vertegenwoordigt.

type IHierarchyIdentityFilterTarget = IQueryNameTarget[]

interface IQueryNameTarget {
    queryName: string;
}
  • queryName: querynaam van de bronkolom in de query. Het komt van de DataViewMetadataColumn
interface IHierarchyIdentityFilterNode<IdentityType> {
    identity: IdentityType;
    children?: IHierarchyIdentityFilterNode<IdentityType>[];
    operator: HierarchyFilterNodeOperators;
}
  • identiteit: De knooppuntidentiteit in DataView. De IdentityType moet zijn CustomVisualOpaqueIdentity

  • onderliggende items: Lijst met knooppunten die relevant zijn voor de huidige selectie

  • operator: De operator voor afzonderlijke objecten in de structuur. De operator kan een van de volgende drie opties zijn:

    type HierarchyFilterNodeOperators = "Selected" | "NotSelected" | "Inherited";
    
    • Geselecteerd: waarde is expliciet geselecteerd.

    • NotSelected: waarde is expliciet niet geselecteerd.

    • Overgenomen: waardeselectie is afhankelijk van de bovenliggende waarde in de hiërarchie of standaard als dit de hoofdwaarde is.

Houd rekening met de volgende regels bij het definiëren van uw hiërarchie-identiteitsfilter:

  • Neem de identiteiten uit de DataView.
  • Elk identiteitspad moet een geldig pad in de DataView zijn.
  • Elk blad moet een operator van Geselecteerd of Niet geselecteerd hebben.
  • Gebruik de ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentities functie om identiteiten te vergelijken.
  • De identiteiten kunnen de volgende velden wijzigen (bijvoorbeeld velden toevoegen of verwijderen). Power BI wijst de bijgewerkte identiteiten toe aan de bestaande filter.hierarchyData.

De API voor het filteren van hiërarchie-identiteiten gebruiken

De volgende code is een voorbeeld van het gebruik van de hiërarchie-id-filter-API in een aangepaste visual:

import { IHierarchyIdentityFilterTarget, IHierarchyIdentityFilterNode, HierarchyIdentityFilter } from "powerbi-models"

const target: IHierarchyIdentityFilterTarget = [];

const hierarchyData: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] = [
    {
        identity: {...},
        operator: "Selected",
        children: [
            {
                identity: {...},
                operator: "NotSelected"
            }
        ]
    },
    {
        identity: {...},
        operator: "Inherited",
        children: [
            {
                identity: {...},
                operator: "Selected"
            }
        ]
    }
];

const filter = new HierarchyIdentityFilter(target, hierarchyData).toJSON();

Gebruik de applyJsonFilter API-aanroep om het filter toe te passen:

this.host.applyJsonFilter(filter, "general", "filter", action);

Als u het actieve JSON-filter wilt herstellen, gebruikt u de jsonFilters eigenschap in VisualUpdateOptions:

export interface VisualUpdateOptions extends extensibility.VisualUpdateOptions {
   //...
   jsonFilters?: IFilter[];
}

Het HierarchyIdnetity filter wordt alleen ondersteund voor hiërarchisch gerelateerde velden. Power BI valideert standaard niet of de velden hiërarchisch zijn gerelateerd.

Als u hiërarchisch gerelateerde validatie wilt activeren, voegt u de eigenschap 'areHierarchically Related' toe aan de relevante rolvoorwaarde in het bestand capabilities.json:

"dataViewMappings": [
    {
         "conditions": [
             {
                  "Rows": {
                      "min": 1,
                      "areHierarchicallyRelated": true <------ NEW ------>
                  },
                  "Value": {
                  "min": 0
                  }
            }
        ],
        ...
    }
]

Velden zijn hiërarchisch gerelateerd als aan de volgende voorwaarden wordt voldaan:

  • Geen opgenomen relatierand is veel tot veel kardinaliteit, noch ConceptualNavigationBehavior.Weak.

  • Alle velden in het filter bestaan in het pad.

  • Elke relatie in het pad heeft dezelfde richting of bidirectioneel.

  • De relatierichting komt overeen met de kardinaliteit voor één tot veel of twee richtingen.

Voorbeeld van hiërarchierelaties

Bijvoorbeeld, op basis van de volgende entiteitsrelatie:

Diagram met de bidirectionele aard van het filter.

  • A, B zijn hiërarchisch gerelateerd: true
  • B, C zijn hiërarchisch gerelateerd: true
  • A, B, C zijn hiërarchisch gerelateerd: true
  • A, C, E zijn hiërarchisch gerelateerd: waar (A --> E --> C)
  • A, B, E zijn hiërarchisch gerelateerd: true (B --> A --> E)
  • A, B, C, E zijn hiërarchisch gerelateerd: true (B --> A --> E --> C)
  • A, B, C, D zijn hiërarchisch gerelateerd: false (geschonden regel 3)
  • C, D zijn hiërarchisch gerelateerd: true
  • B, C, D zijn hiërarchisch gerelateerd: onwaar (geschonden regel 3)
  • A, C, D, E zijn hiërarchisch gerelateerd: onwaar (geschonden regel 3)

Notitie

  • Wanneer deze validaties zijn ingeschakeld en de velden niet hiërarchisch zijn gerelateerd, wordt de visual niet weergegeven en wordt er een foutbericht weergegeven:

    Schermopname van de visual waarvoor validaties zijn ingeschakeld, kan niet worden geladen omdat de velden niet hiërarchisch zijn gerelateerd. In het foutbericht wordt aangegeven dat u velden gebruikt die geen ondersteunde set relaties hebben.

    Schermopname van het foutbericht wanneer validaties zijn ingeschakeld en de velden niet hiërarchisch zijn gerelateerd. Het bericht geeft aan dat deze visual niet kan worden weergegeven.

  • Wanneer deze validaties zijn uitgeschakeld en de filtervisual een filter toepast dat knooppunten bevat die betrekking hebben op niet-hiërarchisch gerelateerde velden, worden andere visuals mogelijk niet goed weergegeven wanneer metingen worden gebruikt:

    Schermopname van visual waarbij validaties zijn uitgeschakeld, kan niet worden geladen omdat de velden niet hiërarchisch zijn gerelateerd. Het foutbericht geeft aan dat de gegevens voor deze visual niet kunnen worden geladen.

    Schermopname van het foutbericht wanneer validaties zijn uitgeschakeld en de velden niet hiërarchisch zijn gerelateerd. Het bericht bevat de tekst 'Kan geen gegevens laden voor deze visual'.

Codevoorbeeld voor het bijwerken van de gegevensstructuur van de hiërarchie na nieuwe selectie

De volgende code laat zien hoe u de hierarchyData structuur bijwerkt na een nieuwe selectie:

type CompareIdentitiesFunc = (id1: CustomVisualOpaqueIdentity, id2: CustomVisualOpaqueIdentity) => boolean;
/**
* Updates the filter tree following a new node selection.
* Prunes irrelevant branches after node insertion/removal if necessary.
* @param path Identities path to the selected node.
* @param treeNodes Array of IHierarchyIdentityFilterNode representing a valid filter tree.
* @param compareIdentities Compare function for CustomVisualOpaqueIdentity to determine equality. Pass the ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentities function.
* @returns A valid filter tree after the update
*/

function updateFilterTreeOnNodeSelection(
   path: CustomVisualOpaqueIdentity[],
   treeNodes: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[],
   compareIdentities: CompareIdentitiesFunc
): IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] {
    if (!path) return treeNodes;
    const root: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
        identity: null,
        children: treeNodes || [],
        operator: 'Inherited',
    };
    let currentNodesLevel = root.children;
    let isClosestSelectedParentSelected = root.operator === 'Selected';
    let parents: { node: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>, index: number }[] = [{ node: root, index: -1 }];
    let shouldFixTree = false;
    path.forEach((identity, level) => {
        const index = currentNodesLevel.findIndex((node) => compareIdentities(node.identity, identity));
        const isLastNodeInPath = level === path.length - 1
        if (index === -1) {
           const newNode: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
               identity,
               children: [],
               operator: isLastNodeInPath ? (isClosestSelectedParentSelected ? 'NotSelected' : 'Selected') : 'Inherited',
           };
           currentNodesLevel.push(newNode);
           currentNodesLevel = newNode.children;
           if (newNode.operator !== 'Inherited') {
              isClosestSelectedParentSelected = newNode.operator === 'Selected';
           }
        } else {
            const currentNode = currentNodesLevel[index];
            if (isLastNodeInPath) {
               const partial = currentNode.children && currentNode.children.length;
               if (partial) {
                  /**
                   * The selected node has subtree.
                   * Therefore, selecting this node should lead to one of the following scenarios:
                   * 1. The node should have Selected operator and its subtree should be pruned.
                   * 2. The node and its subtree should be pruned form the tree and the tree should be fixed.
                   */
                   // The subtree should be always pruned.
                   currentNode.children = [];
                   if (currentNode.operator === 'NotSelected' || (currentNode.operator === 'Inherited' && isClosestSelectedParentSelected )) {
                      /**
                       * 1. The selected node has NotSelected operator.
                       * 2. The selected node has Inherited operator, and its parent has Slected operator.
                       * In both cases the node should be pruned from the tree and the tree shoud be fixed.
                       */
                      currentNode.operator = 'Inherited'; // to ensure it will be pruned
                      parents.push({ node: currentNode, index });
                      shouldFixTree = true;
                  } else {
                     /**
                      * 1. The selected node has Selected operator.
                      * 2. The selected node has Inherited operator, but its parent doesn't have Selected operator.
                      * In both cases the node should stay with Selected operator pruned from the tree and the tree should be fixed.
                      * Note that, node with Selected oprator and parent with Selector operator is not valid state.
                      */
                      currentNode.operator = 'Selected';
                  }
              } else {
                  // Leaf node. The node should be pruned from the tree and the tree should be fixed.
                  currentNode.operator = 'Inherited'; // to ensure it will be pruned
                  parents.push({ node: currentNode, index });
                  shouldFixTree = true;
                 }
             } else {
                 // If it's not the last noded in path we just continue traversing the tree
                 currentNode.children = currentNode.children || [];
                 currentNodesLevel = currentNode.children
                 if (currentNode.operator !== 'Inherited') {
                     isClosestSelectedParentSelected = currentNode.operator === 'Selected';
                     // We only care about the closet parent with Selected/NotSelected operator and its children
                     parents = [];
                  }
                  parents.push({ node: currentNode, index });
                }
           }
    });
    // Prune brnaches with Inherited leaf
    if (shouldFixTree) {
       for (let i = parents.length - 1; i >= 1; i--) {
           // Normalize to empty array
           parents[i].node.children = parents[i].node.children || [];
           if (!parents[i].node.children.length && (parents[i].node.operator === 'Inherited')) {
              // Remove the node from its parent children array
              removeElement(parents[i - 1].node.children, parents[i].index);
           } else {
               // Node has children or Selected/NotSelected operator
               break;
         }
      }
   }
   return root.children;
}
/**
* Removes an element from the array without preserving order.
* @param arr - The array from which to remove the element.
* @param index - The index of the element to be removed.
*/
function removeElement(arr: any[], index: number): void {
    if (!arr || !arr.length || index < 0 || index >= arr.length) return;
    arr[index] = arr[arr.length - 1];
    arr.pop();
}

Overwegingen en beperkingen

  • Dit filter wordt alleen ondersteund voor matrixgegevensweergavetoewijzing.

  • De visual mag slechts één gegevensrol groeperen bevatten.

  • Een visual die gebruikmaakt van het filtertype Hiërarchie-identiteit moet slechts één filter van dit type toepassen.