Modellieren komplexer Datentypen in Azure Cognitive Search

Externe Datasets zum Auffüllen eines Index der kognitiven Azure-Suche können in vielen Formen vorliegen. Manchmal enthalten sie hierarchische oder geschachtelte Unterstrukturen. Beispiele sind mehrere Adressen für einen einzelnen Kunden, mehrere Farben und Größen für eine einzelne SKU, mehrere Autoren für ein einzelnes Buch usw. In der Modelliersprache werden diese Strukturen bisweilen als komplexe, zusammengesetzte, verbundene oder aggregierte Datentypen bezeichnet. Bei der kognitiven Azure-Suche wird für dieses Konzept der Begriff komplexer Typ verwendet. Komplexe Typen werden in Azure Cognitive Search mithilfe komplexer Felder modelliert. Ein komplexes Feld ist ein Feld, das untergeordnete Elemente (untergeordnete Felder) enthält, die einen beliebigen Datentyp aufweisen können – einschließlich anderer komplexer Typen. Dies funktioniert auf ähnliche Weise wie bei strukturierten Datentypen in einer Programmiersprache.

Komplexe Felder stellen je nach Datentyp entweder ein einzelnes Objekt im Dokument oder ein Array von Objekten dar. Felder vom Typ Edm.ComplexType stellen einzelne Objekte dar, während Felder vom Typ Collection(Edm.ComplexType) für Arrays von Objekten stehen.

In der kognitiven Azure-Suche werden komplexe Typen und Sammlungen nativ unterstützt. Mit diesen Typen können Sie nahezu jede JSON-Struktur in einem Index der kognitiven Azure-Suche modellieren. In früheren Versionen von APIs der kognitiven Azure-Suche konnten nur vereinfachte Rowsets importiert werden. In der neuesten Version kann der Index nun genauer den Quelldaten entsprechen. Mit anderen Worten: Wenn die Quelldaten komplexe Typen enthalten, kann auch der Index komplexe Typen enthalten.

Zum Einstieg empfiehlt sich das Dataset „Hotels“, das Sie im Assistenten Daten importieren im Azure-Portal laden können. Im Assistenten werden komplexe Typen in der Quelle erkannt, und es wird basierend auf den erkannten Strukturen ein Indexschema vorgeschlagen.

Hinweis

Die Unterstützung für komplexe Typen ist seit api-version=2019-05-06 allgemein verfügbar.

Wenn Ihre Suchlösung auf früheren Problemumgehungen von vereinfachten Datasets in einer Sammlung aufbaut, sollten Sie den Index so ändern, dass er komplexe Typen enthält, wie sie in der neuesten API-Version unterstützt werden. Weitere Informationen zum Aktualisieren von API-Versionen finden Sie unter Aktualisieren auf die neueste Version der REST-API oder Aktualisieren auf die neueste Version des .NET SDK.

Beispiel für eine komplexe Struktur

Das folgende JSON-Dokument besteht aus einfachen und komplexen Feldern. Komplexe Felder, z. B. Address und Rooms, enthalten Unterfelder. Address umfasst einen einzelnen Wertesatz für diese Unterfelder, da es sich um ein einzelnes Objekt im Dokument handelt. Im Gegensatz dazu umfasst Rooms mehrere Wertesätze für die zugehörigen Unterfelder, jeweils einen Satz für jedes Objekt in der Sammlung.

{
  "HotelId": "1",
  "HotelName": "Secret Point Motel",
  "Description": "Ideally located on the main commercial artery of the city in the heart of New York.",
  "Tags": ["Free wifi", "on-site parking", "indoor pool", "continental breakfast"],
  "Address": {
    "StreetAddress": "677 5th Ave",
    "City": "New York",
    "StateProvince": "NY"
  },
  "Rooms": [
    {
      "Description": "Budget Room, 1 Queen Bed (Cityside)",
      "RoomNumber": 1105,
      "BaseRate": 96.99,
    },
    {
      "Description": "Deluxe Room, 2 Double Beds (City View)",
      "Type": "Deluxe Room",
      "BaseRate": 150.99,
    }
    . . .
  ]
}

Indizieren von komplexen Typen

Für eine Indizierung dürfen maximal 3000 Elemente über alle komplexen Sammlungen hinweg in einem einzelnen Dokument vorhanden sein. Ein Element einer komplexen Sammlung ist ein Member dieser Sammlung, sodass im Fall von Räumen (die einzige komplexe Sammlung im Hotel-Beispiel) jeder Raum ein Element ist. Im obigen Beispiel würde das Hotel-Dokument 500 Raumelemente enthalten, wenn das „Secret Point Motel“ 500 Zimmer hätte. Bei verschachtelten komplexen Sammlungen wird jedes untergeordnete Element ebenfalls gezählt, zusätzlich zu dem äußeren (übergeordneten) Element.

Diese Einschränkung gilt nur für komplexe Sammlungen, nicht für komplexe Typen (wie „Address“) oder Zeichenfolgensammlungen (wie „Tags“).

Erstellen komplexer Felder

Wie jede Indexdefinition können Sie ein Schema, das komplexe Typen enthält, im Portal, mit der REST-API oder mit dem .NET SDK erstellen.

Andere Azure-SDKs enthalten Beispiele in Python, Java und JavaScript.

  1. Melden Sie sich beim Azure-Portal an.

  2. Wählen Sie auf der Seite Übersicht des Suchdiensts die Registerkarte Indizes aus.

  3. Öffnen Sie einen vorhandenen Index, oder erstellen Sie einen neuen Index.

  4. Wählen Sie die Registerkarte Felder und dann Feld hinzufügen aus. Ein leeres Feld wird hinzugefügt. Wenn Sie mit einer vorhandenen Feldauflistung arbeiten, scrollen Sie nach unten, um das Feld einzurichten.

  5. Weisen Sie dem Feld einen Namen zu, und legen Sie den Typ auf Edm.ComplexTypeoder Collection(Edm.ComplexType) fest.

  6. Wählen Sie ganz rechts die Auslassungszeichen und dann entweder Feld hinzufügen oder Untergeordnetes Feld hinzufügen aus. Weisen Sie anschließend Attribute zu.

Aktualisieren komplexer Felder

Alle Neuindizierungsregeln, die allgemein für Felder gelten, gelten auch für komplexe Felder. Eine kurze Wiederholung von einigen Hauptregeln: Das Hinzufügen eines Felds zu einem komplexen Typ erfordert keine Indexneuerstellung, aber die meisten anderen Änderungen erfordern dies.

Strukturelle Aktualisierungen der Definition

Sie können einem komplexen Feld jederzeit neue Unterfelder hinzufügen, ohne dass eine Indexneuerstellung erforderlich ist. Beispielsweise ist es möglich, Address „ZipCode“ oder Rooms „Amenities“ hinzuzufügen, so wie ein Feld auf oberster Ebene einem Index hinzugefügt wird. Vorhandene Dokumente haben einen NULL-Wert für neue Felder, bis Sie diese Felder durch Aktualisieren Ihrer Daten explizit füllen.

Beachten Sie, dass in einem komplexen Typ jedes Unterfeld einen Typ enthält und Attribute enthalten kann, so wie das auch bei übergeordneten Feldern der Fall ist.

Datenaktualisierungen

Die Aktualisierung vorhandener Dokumente in einem Index mit der Aktion upload wird für komplexe und einfache Felder auf identische Weise durchgeführt, d. h., alle Felder werden ersetzt. Jedoch wird merge (oder mergeOrUpload beim Anwenden auf ein vorhandenes Dokument) nicht für alle Felder gleich ausgeführt. Insbesondere unterstützt merge nicht das Zusammenführen von Elementen in einer Sammlung. Dies gilt für Sammlungen von primitiven Typen sowie für komplexe Sammlungen. Zum Aktualisieren einer Sammlung müssen Sie den vollständigen Sammlungswert abrufen, Änderungen vornehmen und dann die neue Sammlung in die Anforderung der Index-API einfügen.

Durchsuchen komplexer Felder

Freiform-Suchausdrücke funktionieren bei komplexen Typen wie erwartet. Wenn ein durchsuchbares Feld oder Unterfeld an beliebiger Stelle in einem Dokument übereinstimmt, ist das Dokument selbst eine Übereinstimmung.

Abfragen werden bei mehreren Begriffen und Operatoren differenzierter, und bei einigen Begriffen sind Feldnamen angegeben, wie das mit der Lucene-Syntax möglich ist. Mit der folgenden Abfrage wird beispielsweise versucht, zwei Begriffe, „Portland“ und „OR“, mit zwei Unterfeldern des Felds „Address“ zu vergleichen:

search=Address/City:Portland AND Address/State:OR

Abfragen wie diese sind im Unterschied zu Filtern nicht korreliert für die Volltextsuche. In Filtern werden Abfragen für untergeordnete Felder einer komplexen Sammlung mithilfe der Bereichsvariablen in any oder all korreliert. Die obige Lucene-Abfrage gibt Dokumente zurück, die „Portland, Maine“ und „Portland, Oregon“ enthalten, sowie andere Städte in Oregon. Dies trifft zu, da jede Klausel für alle Werte des jeweiligen Felds im gesamten Dokument gilt – es gibt also kein Konzept für ein „aktuell untergeordnetes Dokument“. Weitere Informationen hierzu finden Sie unter Grundlegendes zu OData-Sammlungsfiltern in der kognitiven Azure-Suche.

Auswählen komplexer Felder

Über den Parameter $select wird ausgewählt, welche Felder in den Suchergebnissen zurückgegeben werden. Um diesen Parameter zum Auswählen bestimmter Unterfelder eines komplexen Felds zu verwenden, fügen Sie das übergeordnete Feld und das Unterfeld getrennt durch einen Schrägstrich (/) ein.

$select=HotelName, Address/City, Rooms/BaseRate

Felder müssen im Index als „Abrufbar“ markiert sein, wenn sie in den Suchergebnissen enthalten sein sollen. Nur die als „Abrufbar“ markierten Felder können in einer $select-Anweisung verwendet werden.

Filtern, Faceting und Sortieren komplexer Felder

Die für die Filterung und für feldbezogene Suchen verwendete OData-Pfadsyntax kann auch für das Faceting, die Sortierung und die Auswahl von Feldern in einer Suchanforderung verwendet werden. Für komplexe Typen gelten Regeln, mit denen gesteuert wird, welche Unterfelder als sortierbar oder facettierbar markiert werden können. Weitere Informationen zu diesen Regeln finden Sie in der Referenz zur API zur Indexerstellung.

Faceting von Unterfeldern

Jedes Unterfeld kann als facettierbar markiert werden, mit Ausnahme von Feldern der Typen Edm.GeographyPoint und Collection(Edm.GeographyPoint).

Die in den Facettenergebnissen zurückgegebene Anzahl von Dokumenten wird für das übergeordnete Dokument (ein Hotel) berechnet, nicht für die untergeordneten Dokumente in einer komplexen Sammlung (Zimmer). Beispiel: Ein Hotel hat 20 Zimmer vom Typ „suite“. Für den facettierten Parameter facet=Rooms/Type lautet die Anzahl der Facetten für das Hotel 1, nicht 20 für die Zimmer.

Sortieren komplexer Felder

Sortiervorgänge gelten für Dokumente (Hotels) und nicht für Unterdokumente (Zimmer). Bei einer Sammlung von komplexen Typen, z. B. „Rooms“ (Zimmer), ist es wichtig zu wissen, dass für „Rooms“ keinerlei Sortiervorgänge durchgeführt werden können. Sortiervorgänge können für keine Sammlung durchgeführt werden.

Sortiervorgänge sind möglich, wenn Felder in einem Dokument einwertig sind. Dabei kann es sich um einfache Felder oder um Unterfelder in einem komplexen Typ handeln. Address/City darf z. B. sortierbar sein, da es nur eine Adresse pro Hotel gibt, $orderby=Address/City sortiert die Hotels also nach der Stadt.

Filtern komplexer Felder

Sie können auf die untergeordneten Felder eines komplexen Felds in einem Filterausdruck verweisen. Verwenden Sie einfach die gleiche OData-Pfadsyntax wie für die Facettierung, Sortierung und Auswahl von Feldern. Der folgende Filter gibt z. B. alle Hotels in Kanada zurück:

$filter=Address/Country eq 'Canada'

Um nach einem Feld in einer komplexen Sammlung zu filtern, können Sie einen Lambdaausdruck mit den Operatoren any und all verwenden. In diesem Fall ist die Bereichsvariable des Lambdaausdrucks ein Objekt mit untergeordneten Feldern. Sie können auf diese untergeordneten Felder mit der OData-Standardpfadsyntax verweisen. Der folgende Filter gibt beispielsweise alle Hotels zurück, die mindestens ein Luxuszimmer und ausschließlich Nichtraucherzimmer haben:

$filter=Rooms/any(room: room/Type eq 'Deluxe Room') and Rooms/all(room: not room/SmokingAllowed)

Wie schon bei einfachen Feldern der obersten Ebene können auch einfache untergeordnete Felder von komplexen Feldern nur in Filtern verwendet werden, wenn Ihr filterable-Attribut in der Indexdefinition auf true festgelegt wurde. Weitere Informationen finden Sie in der Referenz zur API zur Indexerstellung.

Nächste Schritte

Testen Sie das Dataset „Hotels“ im Assistenten Daten importieren. Für den Zugriff auf die Daten benötigen Sie die in der Infodatei angegebenen Azure Cosmos DB-Verbindungsinformationen.

Mit diesen Informationen erstellen Sie im ersten Schritt im Assistenten eine neue Azure Cosmos DB-Datenquelle. Später im Assistenten, wird auf der Seite für den Zielindex ein Index mit komplexen Typen angezeigt. Erstellen und laden Sie diesen Index, und führen Sie dann Abfragen aus, um sich mit der neuen Struktur vertraut zu machen.