Modelování složitých datových typů ve službě Azure AI Search

Externí datové sady používané k naplnění indexu Azure AI Search můžou mít mnoho obrazců. Někdy zahrnují hierarchické nebo vnořené podstruktury. Příkladem může být několik adres pro jednoho zákazníka, více barev a velikostí pro jednu skladovou položku, více autorů jedné knihy atd. V modelingu se tyto struktury můžou zobrazovat jako složité, složené, složené nebo agregované datové typy. Termín Azure AI Search používá pro tento koncept komplexní typ. Ve službě Azure AI Search se komplexní typy modelují pomocí složitých polí. Komplexní pole je pole, které obsahuje podřízené pole (podpole), které mohou být libovolného datového typu, včetně jiných složitých typů. Funguje to podobným způsobem jako strukturované datové typy v programovacím jazyce.

Složitá pole představují jeden objekt v dokumentu nebo pole objektů v závislosti na datovém typu. Pole typu Edm.ComplexType představují jednotlivé objekty, zatímco pole typu Collection(Edm.ComplexType) představují pole objektů.

Azure AI Search nativně podporuje komplexní typy a kolekce. Tyto typy umožňují modelovat téměř jakoukoli strukturu JSON v indexu Azure AI Search. V předchozích verzích rozhraní API služby Azure AI Search bylo možné importovat pouze sady plochých řádků. V nejnovější verzi teď index může přesněji odpovídat zdrojovým datům. Jinými slovy, pokud zdrojová data mají složité typy, může mít index také složité typy.

Pro začátek doporučujeme sadu dat Hotels, kterou můžete načíst v průvodci importem dat na webu Azure Portal. Průvodce zjistí složité typy ve zdroji a navrhne schéma indexu na základě zjištěných struktur.

Poznámka:

Podpora komplexních typů byla obecně dostupná od začátku api-version=2019-05-06.

Pokud je vaše řešení vyhledávání postavené na dřívějších alternativních řešeních zploštěných datových sad v kolekci, měli byste změnit index tak, aby zahrnoval složité typy podporované v nejnovější verzi rozhraní API. Další informace o upgradu verzí rozhraní API najdete v tématu Upgrade na nejnovější verzi rozhraní REST API nebo upgrade na nejnovější verzi sady .NET SDK.

Příklad komplexní struktury

Následující dokument JSON se skládá z jednoduchých polí a složitých polí. Složitá pole, například Address a Rooms, mají dílčí pole. Address obsahuje jednu sadu hodnot pro tato dílčí pole, protože se jedná o jeden objekt v dokumentu. Naproti tomu Rooms má několik sad hodnot pro jeho dílčí pole, jeden pro každý objekt v kolekci.

{
  "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,
    }
    . . .
  ]
}

Indexování složitých typů

Během indexování můžete mít maximálně 3000 prvků ve všech složitých kolekcích v rámci jednoho dokumentu. Prvek komplexní kolekce je členem této kolekce, takže v případě místností (jediná složitá kolekce v příkladu hotelu) je každý pokoj prvkem. V předchozím příkladu by pokud "Secret Point Motel" měl 500 pokojů, hotelový dokument by měl 500 prvků místnosti. U vnořených komplexních kolekcí se počítá také každý vnořený prvek kromě vnějšího (nadřazeného) elementu.

Tento limit platí jenom pro složité kolekce a ne pro komplexní typy (například Adresy) nebo kolekce řetězců (například Značky).

Vytváření složitých polí

Stejně jako u jakékoli definice indexu můžete pomocí portálu, rozhraní REST API nebo sady .NET SDK vytvořit schéma, které zahrnuje komplexní typy.

Další sady Azure SDK poskytují ukázky v Pythonu, Javě a JavaScriptu.

  1. Přihlaste se k portálu Azure.

  2. Na stránce Přehled vyhledávací služby vyberte kartu Indexy.

  3. Otevřete existující index nebo vytvořte nový index.

  4. Vyberte kartu Pole a pak vyberte Přidat pole. Přidá se prázdné pole. Pokud pracujete s existující kolekcí polí, posuňte se dolů a nastavte pole.

  5. Zadejte název pole a nastavte typ buď nebo Edm.ComplexTypeCollection(Edm.ComplexType).

  6. Vyberte tři tečky úplně vpravo a pak vyberte přidat pole nebo přidat dílčí pole a pak přiřaďte atributy.

Aktualizace složitých polí

Všechna pravidla přeindexování, která platí pro pole obecně platí pro složitá pole. Když tady přidáte pole do komplexního typu, přepočítáte několik hlavních pravidel, nebude vyžadovat opětovné sestavení indexu, ale většinu změn se provede.

Strukturální aktualizace definice

Do komplexního pole můžete kdykoli přidat nová dílčí pole bez nutnosti opětovného sestavení indexu. Například přidání psčovacího kódu do nebo "Vybavení" je AddressRooms povolené, stejně jako přidání pole nejvyšší úrovně do indexu. Existující dokumenty mají hodnotu null pro nová pole, dokud tato pole explicitně nenaplníte aktualizací dat.

Všimněte si, že v rámci komplexního typu má každé dílčí pole typ a může mít atributy, stejně jako pole nejvyšší úrovně.

Aktualizace dat

Aktualizace existujících dokumentů v indexu akcí upload funguje stejně pro složitá a jednoduchá pole: všechna pole se nahradí. ( merge nebo mergeOrUpload při použití u existujícího dokumentu) ale ve všech polích nefunguje stejně. Konkrétně merge nepodporuje slučování prvků v kolekci. Toto omezení platí pro kolekce primitivních typů a složitých kolekcí. Pokud chcete aktualizovat kolekci, musíte načíst úplnou hodnotu kolekce, provést změny a pak zahrnout novou kolekci do požadavku rozhraní API indexu.

Hledání složitých polí

Výrazy pro vyhledávání ve volném formátu fungují podle očekávání se složitými typy. Pokud se libovolné prohledávatelné pole nebo dílčí pole kdekoli v dokumentu shoduje, pak se samotný dokument shoduje.

Dotazy mají větší nuance, pokud máte více termínů a operátorů a některé termíny mají zadané názvy polí, co je to možné pomocí syntaxe Lucene. Tento dotaz se například pokusí shodovat se dvěma termíny: "Portland" a "OR" proti dvěma dílčím polím pole Adresa:

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

Podobné dotazy nesouvisejí s fulltextovým vyhledáváním, na rozdíl od filtrů. Ve filtrech jsou dotazy nad dílčími poli komplexní kolekce korelovány pomocí proměnných rozsahu v any nebo all. Výše uvedený dotaz Lucene vrátí dokumenty obsahující "Portland, Maine" a "Portland, Oregon", spolu s dalšími městy v Oregonu. K tomu dochází, protože každá klauzule se vztahuje na všechny hodnoty jeho pole v celém dokumentu, takže neexistuje žádný koncept "aktuálního vnořeného dokumentu". Další informace najdete v tématu Principy filtrů kolekce OData ve službě Azure AI Search.

Výběr složitých polí

Parametr $select slouží k výběru polí vrácených ve výsledcích hledání. Chcete-li tento parametr použít k výběru konkrétních dílčích polí komplexního pole, zahrňte nadřazené pole a dílčí pole oddělené lomítkem (/).

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

Pole musí být v indexu označena jako Načístelná, pokud je chcete mít ve výsledcích hledání. V příkazu lze použít $select pouze pole označená jako Retrievable.

Filtrování, omezující vlastnost a řazení složitých polí

Stejnou syntaxi cesty OData, která se používá pro filtrování a vyhledávání v polích, lze také použít pro fasety, řazení a výběr polí v požadavku hledání. U složitých typů platí pravidla, která určují, která dílčí pole je možné označit jako řaditelná nebo omezující. Další informace o těchto pravidlech najdete v referenčních informacích k rozhraní API pro vytvoření indexu.

Fasetové dílčí pole

Jakékoli dílčí pole lze označit jako omezující, pokud není typu Edm.GeographyPoint nebo Collection(Edm.GeographyPoint).

Počty dokumentů vrácené ve výsledcích omezující vlastnosti se počítají pro nadřazený dokument (hotel), ne pro vnořené dokumenty v komplexní kolekci (místnosti). Předpokládejme například, že hotel má 20 pokojů typu "suite". Vzhledem k tomuto parametru facet=Rooms/Typeomezující vlastnosti je počet omezujících vlastností jeden pro hotel, nikoli 20 pro pokoje.

Řazení složitých polí

Operace řazení se vztahují na dokumenty (Hotely) a ne na vnořené dokumenty (Místnosti). Pokud máte složitou kolekci typů, například Místnosti, je důležité si uvědomit, že se vůbec nedá řadit podle místností. Ve skutečnosti nemůžete řadit podle žádné kolekce.

Operace řazení fungují, když pole mají jednu hodnotu na dokument, ať už jde o jednoduché pole, nebo dílčí pole v komplexním typu. Je například možné řadit, Address/City protože na hotel je jenom jedna adresa, takže $orderby=Address/City seřadí hotely podle města.

Filtrování komplexních polí

Ve výrazu filtru můžete odkazovat na dílčí pole komplexního pole. Stačí použít stejnou syntaxi cesty OData, která se používá k fasetování, řazení a výběru polí. Například následující filtr vrátí všechny hotely v Kanadě:

$filter=Address/Country eq 'Canada'

Pokud chcete filtrovat komplexní pole kolekce, můžete použít výraz lambda s operátory a all operátoryany. V takovém případě je proměnná rozsahu výrazu lambda objektem s dílčími poli. Na tato podpole můžete odkazovat pomocí standardní syntaxe cesty OData. Například následující filtr vrátí všechny hotely s alespoň jedním pokojem deluxe a všemi nesmokovacími místnostmi:

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

Stejně jako u jednoduchých polí nejvyšší úrovně je možné do filtrů zahrnout pouze jednoduchá dílčí pole komplexních polí, pokud mají filtrovatelný atribut nastavený na true definici indexu. Další informace najdete v referenčních informacích k rozhraní API pro vytvoření indexu.

Azure Search má omezení, že složité objekty v kolekcích v jednom dokumentu nesmí překročit 3000.

Uživatelům se při indexování zobrazí následující chyba, když složitá kolekce překročí limit 3000.

"Kolekce v dokumentu překračuje maximální počet prvků ve všech složitých kolekcích. Dokument s klíčem 1052 obsahuje objekty 4303 v kolekcích (pole JSON). Maximálně 3000 objektů může být v kolekcích v celém dokumentu. Odeberte objekty z kolekcí a zkuste dokument znovu indexovat."

V některých případech použití může být potřeba do kolekce přidat více než 3000 položek. V těchto případech použití můžeme předvést (|) nebo použít libovolnou formu oddělovače k oddělovači hodnot, zřetězení a jejich uložení jako řetězec s oddělovači. Počet řetězců uložených v poli ve službě Azure Search není nijak omezený. Uložení těchto složitých hodnot jako řetězců zabrání omezení. Zákazník musí ověřit, jestli toto alternativní řešení splňuje požadavky na scénář.

Například není možné použít složité typy, pokud pole "searchScope" níže mělo více než 3 000 prvků.


"searchScope": [
  {
     "countryCode": "FRA",
     "productCode": 1234,
     "categoryCode": "C100" 
  },
  {
     "countryCode": "USA",
     "productCode": 1235,
     "categoryCode": "C200" 
  }
]

Uložení těchto složitých hodnot jako řetězců s oddělovačem zabrání omezení.

"searchScope": [
        "|FRA|1234|C100|",
        "|FRA|*|*|",
        "|*|1234|*|",
        "|*|*|C100|",
        "|FRA|*|C100|",
        "|*|1234|C100|"
]

Místo uložení pomocí zástupných znaků můžeme také použít vlastní analyzátor , který rozdělí slovo na | a sníží velikost úložiště.

Důvod, proč jsme hodnoty uložili se zástupnými cardy, místo aby je ukládali jako níže.

|FRA|1234|C100|

je určena pro scénáře hledání, ve kterých může zákazník chtít hledat položky, které mají zemi Francie, bez ohledu na produkty a kategorie. Podobně může zákazník muset hledat, aby zjistil, jestli položka obsahuje produkt 1234 bez ohledu na zemi nebo kategorii.

Pokud jsme uložili jenom jednu položku

|FRA|1234|C100|

bez zástupných znaků, pokud chce uživatel filtrovat pouze ve Francii, nemůžeme převést vstup uživatele tak, aby odpovídal poli "searchScope", protože nevíme, jaká kombinace Francie je přítomna v našem poli "searchScope".

Pokud chce uživatel filtrovat jenom podle země, řekněme Francie. Vezmeme uživatelský vstup a vytvoříme ho jako řetězec, jak je znázorněno níže:

|FRA|*|*|

které pak můžeme použít k filtrování ve službě Azure Search při hledání v poli hodnot položek.

foreach (var filterItem in filterCombinations)
        {
            var formattedCondition = $"searchScope/any(s: s eq '{filterItem}')";
            combFilter.Append(combFilter.Length > 0 ? " or (" + formattedCondition + ")" : "(" + formattedCondition + ")");
        }

Podobně platí, že pokud uživatel hledá Francii a kód produktu 1234, vezmeme uživatelský vstup, vytvoříme ho jako řetězec s oddělovači jako níže a porovnáme ho s naším vyhledávacím polem.

|FRA|1234|*|

Pokud uživatel vyhledá kód produktu 1234, vezmeme uživatelský vstup, vytvoříme ho jako řetězec s oddělovači jako níže a porovnáme ho s naším vyhledávacím polem.

|*|1234|*|

Pokud uživatel vyhledá kód kategorie C100, vezmeme uživatelský vstup, vytvoříme ho jako řetězec s oddělovači, jak je uvedeno níže, a porovnáme ho s naším vyhledávacím polem.

|*|*|C100|

Pokud uživatel vyhledá Francie a kód kategorie 1234 a C100, vezmeme uživatelský vstup, vytvoříme ho jako řetězec s oddělovači jako níže a porovnáme ho s naším vyhledávacím polem.

|FRA|1234|C100|

Pokud se uživatel pokusí vyhledat země, které nejsou v našem seznamu, nebude odpovídat poli s oddělovači "searchScope" uloženým v indexu vyhledávání a nebudou vráceny žádné výsledky. Uživatel například vyhledá Kanadu a kód produktu 1234. Vyhledávání uživatelů by bylo převedeno na

|CAN|1234|*|

Nebude se shodovat s žádnou položkou v poli s oddělovači v našem vyhledávacím indexu.

Pouze výše uvedená volba návrhu vyžaduje tuto položku se zástupným znakem; pokud byl uložen jako složitý objekt, mohli jsme jednoduše provést explicitní vyhledávání, jak je znázorněno níže.

           var countryFilter = $"searchScope/any(ss: search.in(countryCode ,'FRA'))";
            var catgFilter = $"searchScope/any(ss: search.in(categoryCode ,'C100'))";
            var combinedCountryCategoryFilter = "(" + countryFilter + " and " + catgFilter + ")";

Proto můžeme splnit požadavky, kdy potřebujeme vyhledat kombinaci hodnot tak, že ji uložíme jako řetězec s oddělovači místo složité kolekce, pokud naše komplexní kolekce překročí limit služby Azure Search. Toto je jedno z alternativních řešení a zákazník musí ověřit, jestli splňuje požadavky na scénář.

Další kroky

Vyzkoušejte sadu dat Hotels v průvodci importem dat. Pro přístup k datům potřebujete informace o připojení ke službě Azure Cosmos DB uvedené v souboru readme.

Po ruce s informacemi je prvním krokem v průvodci vytvoření nového zdroje dat Azure Cosmos DB. Dále v průvodci, když se dostanete na cílovou indexovou stránku, uvidíte index se složitými typy. Vytvořte a načtěte tento index a potom spusťte dotazy, abyste porozuměli nové struktuře.