Power Automate mit SharePoint Search REST API beschleunigen

von Roland Rickborn
Power Automate beschleunigen

Einführung

In diesem "Quick Tipp" stelle ich eine pragmatische Lösung vor, wie man Power Automate Flows in Verbindung mit der SharePoint Search REST API beschleunigen kann.

Überblick der Problematik bei der Verwendung der SharePoint Search REST API

Aus meiner Sicht hat die SharePoint Search REST API [1] einige Fehler oder Nachteile, die das Arbeiten mit der Schnittstelle erschweren. Dies trifft besonders auf die Verarbeitung von JSON-Daten in Power Automate zu, wo die Möglichkeiten der Programmierung durch die Umgebung relativ eng begrenzt sind. Meiner Meinung nach sind die drei größten Schwachpunkte der API:

  • die Daten, die die Schnittstelle liefert, sind mehrfach ineinander verschachtelt. Die eigentlichen Ergebnisse findet man in Zellen, die sich in Zeilen befinden, die zu einer Tabelle gehören.
  • das Tabellen-Format bedingt auch, dass die eigentlichen Ergebnisse nicht in Form von Schlüssel-Wert-Paaren zurück geliefert werden. Das macht den schnellen Zugriff auf bestimmte Werte extrem kompliziert und sorgt in Power Automate für sehr lange Laufzeiten.
  • die Anzahl der zurückgegebenen Schlüssel-Wert-Paare läßt sich nicht genau beeinflussen. Mittels des Parameters SelectProperties lässt sich zwar bestimmen, welche Eigenschaften man auf jeden Fall im Ergebnis erhalten möchte. Aber der Rückgabewert wird nicht auf die in diesem Parameter definierten Eigenschaften beschränkt.

JSON Schema der SharePoint Search REST API

{
    "type": "object",
    "properties": {
        "d": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "object",
                    "properties": {
                        "__metadata": {
                            "type": "object",
                            "properties": {
                                "type": {
                                    "type": "string"
                                }
                            }
                        },
                        "ElapsedTime": {
                            "type": "integer"
                        },
                        "PrimaryQueryResult": {
                            "type": "object",
                            "properties": {
                                "__metadata": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "CustomResults": {
                                    "type": "object",
                                    "properties": {
                                        "__metadata": {
                                            "type": "object",
                                            "properties": {
                                                "type": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "results": {
                                            "type": "array"
                                        }
                                    }
                                },
                                "QueryId": {
                                    "type": "string"
                                },
                                "QueryRuleId": {
                                    "type": "string"
                                },
                                "RefinementResults": {},
                                "RelevantResults": {
                                    "type": "object",
                                    "properties": {
                                        "__metadata": {
                                            "type": "object",
                                            "properties": {
                                                "type": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "GroupTemplateId": {},
                                        "ItemTemplateId": {},
                                        "Properties": {
                                            "type": "object",
                                            "properties": {
                                                "__metadata": {
                                                    "type": "object",
                                                    "properties": {
                                                        "type": {
                                                            "type": "string"
                                                        }
                                                    }
                                                },
                                                "results": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "Key": {
                                                                "type": "string"
                                                            },
                                                            "Value": {
                                                                "type": "string"
                                                            },
                                                            "ValueType": {
                                                                "type": "string"
                                                            }
                                                        },
                                                        "required": [
                                                            "Key",
                                                            "Value",
                                                            "ValueType"
                                                        ]
                                                    }
                                                }
                                            }
                                        },
                                        "ResultTitle": {},
                                        "ResultTitleUrl": {},
                                        "RowCount": {
                                            "type": "integer"
                                        },
                                        "Table": {
                                            "type": "object",
                                            "properties": {
                                                "__metadata": {
                                                    "type": "object",
                                                    "properties": {
                                                        "type": {
                                                            "type": "string"
                                                        }
                                                    }
                                                },
                                                "Rows": {
                                                    "type": "object",
                                                    "properties": {
                                                        "results": {
                                                            "type": "array",
                                                            "items": {
                                                                "type": "object",
                                                                "properties": {
                                                                    "__metadata": {
                                                                        "type": "object",
                                                                        "properties": {
                                                                            "type": {
                                                                                "type": "string"
                                                                            }
                                                                        }
                                                                    },
                                                                    "Cells": {
                                                                        "type": "object",
                                                                        "properties": {
                                                                            "results": {
                                                                                "type": "array",
                                                                                "items": {
                                                                                    "type": "object",
                                                                                    "properties": {
                                                                                        "__metadata": {
                                                                                            "type": "object",
                                                                                            "properties": {
                                                                                                "type": {
                                                                                                    "type": "string"
                                                                                                }
                                                                                            }
                                                                                        },
                                                                                        "Key": {
                                                                                            "type": "string"
                                                                                        },
                                                                                        "Value": {
                                                                                            "type": "string"
                                                                                        },
                                                                                        "ValueType": {
                                                                                            "type": "string"
                                                                                        }
                                                                                    },
                                                                                    "required": [
                                                                                        "__metadata",
                                                                                        "Key",
                                                                                        "Value",
                                                                                        "ValueType"
                                                                                    ]
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                },
                                                                "required": [
                                                                    "__metadata",
                                                                    "Cells"
                                                                ]
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "TotalRows": {
                                            "type": "integer"
                                        },
                                        "TotalRowsIncludingDuplicates": {
                                            "type": "integer"
                                        }
                                    }
                                },
                                "SpecialTermResults": {}
                            }
                        },
                        "Properties": {
                            "type": "object",
                            "properties": {
                                "__metadata": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "results": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "Key": {
                                                "type": "string"
                                            },
                                            "Value": {
                                                "type": "string"
                                            },
                                            "ValueType": {
                                                "type": "string"
                                            }
                                        },
                                        "required": [
                                            "Key",
                                            "Value",
                                            "ValueType"
                                        ]
                                    }
                                }
                            }
                        },
                        "SecondaryQueryResults": {
                            "type": "object",
                            "properties": {
                                "__metadata": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "results": {
                                    "type": "array"
                                }
                            }
                        },
                        "SpellingSuggestion": {},
                        "TriggeredRules": {
                            "type": "object",
                            "properties": {
                                "__metadata": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "results": {
                                    "type": "array"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Das oben gezeigte JSON Schema wird so von Power Automate mit dem Schritt JSON analysieren vorgeschlagen, wenn man die ursprünglichen JSON-Daten einer Abfrage an die SharePoint Search REST API verwendet. Daran sieht man schon, dass die Verarbeitung solcher JSON-Daten nicht trivial ist. Zudem ist das von Power Automate vorgeschlagene JSON Schema nicht verwendbar, weil manche Eigentschaften fest dem Typ String zugewiesen werden, die aber in der Realität teilweise auch Null-Werte enthalten. Es ist also angeraten, die Type-Definitionen wie folgt zu ändern, falls man mit diesem Schema und auf die herkömliche Weise JSON-Daten in Power Automate verarbeiten möchte.

Angepaßte Typ-Definition in JSON

"type": {
    "type": ["string", "null"]
}

Ein Result wird von der SharePoint Search REST API folgendermaßen zurückgegeben, wobei ich hier die Anzahl der Schlüssel-Wert-Paare bereits gekürzt habe.

JSON Objekt (gekürzt)

{
    "Cells": {
        "results": [{
                "__metadata": {
                    "type": "SP.KeyValue"
                },
                "Key": "IsDocument",
                "Value": "false",
                "ValueType": "Edm.Boolean"
            },
            {
                "__metadata": {
                    "type": "SP.KeyValue"
                },
                "Key": "UniqueId",
                "Value": "{E5FD972D-DCE1-4F04-B5A6-94FBE20C1E40}",
                "ValueType": "Edm.String"
            },
            {
                "__metadata": {
                    "type": "SP.KeyValue"
                },
                "Key": "Path",
                "Value": "https://xxx",
                "ValueType": "Edm.String"
            }
        ]
    }
}

Problemstellung beim Verarbeiten von Daten der SharePoint Search REST API

Möchte man auf eine bestimmte Eigenschaft eines Ergebnisses der SharePoint Search REST API zugreifen, so muss man im Rückgabewert der Schnittstelle nach dieser Eigenschaft suchen. Als Beispiel möchte ich eine Liste aller UniqueID erhalten, die bei der Suche nach dem Begriff "Test" von der SharePoint-Suche als Ergebnis zurückgegeben werden. Meine Such-Abfrage lautet:

GET-Request an SharePoint Search REST API

/_api/search/query?querytext='test'&selectproperties='UniqueId'&rowlimit=10

Entsprechend dem oben dargestellten JSON-Schema enthält der Rückgabewert der Schnittstelle 10 Zellen-Ergebnisse (Cells->results). Jedes dieser Ergebnisse enthält wiederum 18 Schlüssel-Wert-Paare - und trotz der Angabe des Parameters "selectproperties='UniqueId'". Um an die gewünschen Daten zu gelangen, muss man also den vollständigen Rückgabewert in mehreren Schleifen komplett durchlaufen. Zuerst muss man alle Cells durchlaufen. In jeder Zelle müssen alle Keys durchlaufen werden. Jede Schlüssel muss dann mit dem gesuchten Schlüssel UniqueId verglichen werden. Liegt eine Übereinstimmung vor, hat man also das gesuchte Schlüssel-Wert-Paar gefunden, dann muss der aktuelle Wert notiert werden (an ein Array angefügt werden). Die nachfolgenden Bilder vermitteln den Aufbau des Flows entsprechend.

Darstellung der zweifachen Schleife in Power Automate

Darstellung der zweifachen Schleife in Power Automate
Darstellung der zweifachen Schleife in Power Automate inkl. Überprüfung des Schlüssels und Hinzufügen zum Array bei Zutreffen

Das Durchlaufen der zweichfachen Schleife dauert in Power Automate bei 10 Datensätzen ca. 25,7 Sekunden - viel zu lange!

Flow Ausführung mit Angabe der DauerGenerell sind Schleifen in Power Automate langsam. Im vorliegenden Fall wird die innere Schleife 10-mal gestartet, wodurch der ganze Flow sehr lange läuft.

Lösungsansatz: JSON-Daten vor der Verarbeitung konvertieren

Die Idee ist, die innere Schleife zu vermeiden. Um das zu erreichen, müssten die JSON-Daten vor der Verarbeitung in ein Schema überführt werden, welches für die Verarbeitung besser geeignet ist. Ich stelle mir ein Schema mit einem richtigen Schlüssel-Wert-Paar vor, beispielsweise so:

Konvertiertes JSON Objekt (gekürzt)

[
  {
    "IsDocument": "false",
    "UniqueId": "{E5FD972D-DCE1-4F04-B5A6-94FBE20C1E40}",
    "Path": "https://xxx"
  }
]

Das konvertierte JSON Objekt macht einen direkten Zugriff auf den Wert eines Schlüssels möglich. Dadurch entfällt die innere Schleife, in der nach dem gewünschten Schlüssel gesucht wird.

Aufgrund der Limitierungen im Standardfunktionsumfang von Power Automate habe ich mich hauptsächlich auf die Funktion replace konzentriert. Der nachfolgende Ausdruck in einem Verfassen-Schritt sorgt für die notwendige Konvertierung der JSON-Daten.

Der unten genannte Konvertierungsschritt funktioniert nur, wenn zuvor beim HTTP Request folgende HTTP Header verwendet wurden:

Name Wert
accept application/json;odata=verbose
content-type application/json;odata=verbose

JSON-Daten konvertieren

@{json(replace(replace(replace(replace(replace(replace(replace(replace(replace(string(outputs('HTTP-Anforderung_an_SharePoint_senden')?['body']['d']['query']['PrimaryQueryResult']['RelevantResults']['Table']['Rows']['results']),'"Key":',''),',"Value"',''),'{"__metadata":{"type":"SP.SimpleDataRow"},"Cells":{"results":',''),']}}',']'),'"__metadata":{"type":"SP.KeyValue"},',''),'{"','"'),'"}','"'),'["','{"'),'"]','"}'))}

JSON-String konvertierenDabei werden die JSON-Daten aus dem Rückgabewert der REST API zuerst in eine Zeichenkette verwandelt. Danach werden nacheinander bestimmte Zeichenketten gelöscht bzw. ersetzt. Am Ende wird aus der restlichen Zeichenkette wieder ein JSON Objekt gemacht.

Mit den konvertieren JSON-Daten ist in Power Automate nur noch eine Schleife notwendig. In dieser Schleife kann mit einem Schlüssel direkt auf dessen Wert zugegriffen werden, also:

@{items('Auf_alle_anwenden')?['UniqueId']}

Durch die vorherige Konvertierung der JSON-Daten verringert sich die Dauer des Flows auf 2,26 Sekunden.

Stark verkürzte Dauer des Flows

Fazit zu vorgeschlagenen Beschelunigung in Verbindung mit der SharePoint Search REST API

Die vorgeschlagene Lösung ist sehr pragmatisch. Replace-Aktionen an einem JSON-String sind immer kritisch zu sehen. Andererseits ist der Zeitgewinn durch das verbesserte JSON-Schema nach der Konvertierung enorm.

Zurück

© 2006-2024 exensio GmbH
Einstellungen gespeichert
Datenschutzeinstellungen

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:

 

  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
You are using an outdated browser. The website may not be displayed correctly. Close