Összetett adattípusok modellezése az Azure AI Searchben
Az Azure AI Search-indexek feltöltéséhez használt külső adatkészletek számos alakzatban lehetnek. Néha hierarchikus vagy beágyazott alstruktúrákat is tartalmaznak. Ilyen lehet például egy ügyfél több címe, egy termék több színe és mérete, egy könyv több szerzője stb. Modellezési szempontból ezeket a struktúrákat összetett, összetett, összetett vagy összesítő adattípusoknak nevezik. Az Azure AI Search kifejezés ehhez a fogalomhoz összetett típus. Az Azure AI Searchben az összetett típusok modellezése összetett mezők használatával történik. Az összetett mező olyan mező, amely gyermekeket (almezőket) tartalmaz, amelyek bármilyen típusúak lehetnek, beleértve az egyéb összetett típusokat is. Ez a programozási nyelv strukturált adattípusaihoz hasonlóan működik.
Az összetett mezők a dokumentum egyetlen objektumát vagy egy objektumtömböt jelölnek az adattípustól függően. A típusmezők Edm.ComplexType
egyetlen objektumot, míg a típusmezők Collection(Edm.ComplexType)
objektumtömböket jelölnek.
Az Azure AI Search natív módon támogatja az összetett típusokat és gyűjteményeket. Ezek a típusok lehetővé teszik, hogy szinte bármilyen JSON-struktúrát modellezhet egy Azure AI Search-indexben. Az Azure AI Search API-k korábbi verzióiban csak az egybesimított sorkészletek importálhatók. A legújabb verzióban az index mostantól jobban megfelelhet a forrásadatoknak. Más szóval, ha a forrásadatok összetett típusok, akkor az index összetett típusokkal is rendelkezhet.
Első lépésként javasoljuk a Hotels adatkészletet, amelyet az Adatok importálása varázslóban tölthet be az Azure Portalon. A varázsló összetett típusokat észlel a forrásban, és javaslatot tesz egy indexsémára az észlelt struktúrák alapján.
Feljegyzés
Az összetett típusok támogatása általánosan elérhetővé vált a következőtől api-version=2019-05-06
kezdve: .
Ha a keresési megoldás egy gyűjtemény lapított adathalmazainak korábbi kerülő megoldásaira épül, az indexet úgy kell módosítania, hogy a legújabb API-verzióban támogatott összetett típusokat is tartalmazzon. További információ az API-verziók frissítéséről: Frissítés a legújabb REST API-verzióra vagy frissítés a legújabb .NET SDK-verzióra.
Példa egy összetett struktúrára
A következő JSON-dokumentum egyszerű mezőkből és összetett mezőkből áll. Az összetett mezők( például Address
és Rooms
) almezőkkel rendelkeznek. Address
egyetlen értékkészlettel rendelkezik ezekhez az almezőkhöz, mivel ez egy objektum a dokumentumban. Ezzel szemben Rooms
az almezőkhöz több értékkészlet tartozik, egy a gyűjtemény minden objektumához.
{
"HotelId": "1",
"HotelName": "Stay-Kay City Hotel",
"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,
}
. . .
]
}
Összetett mezők létrehozása
Az indexdefiníciókhoz hasonlóan a portál, a REST API vagy a .NET SDK használatával is létrehozhat egy összetett típusokat tartalmazó sémát.
Más Azure SDK-k pythonos, Java- és JavaScript-mintákat biztosítanak.
Jelentkezzen be az Azure Portalra.
A keresési szolgáltatás Áttekintés lapján válassza az Indexek lapot.
Nyisson meg egy meglévő indexet, vagy hozzon létre egy új indexet.
Válassza a Mezők lapot, majd a Mező hozzáadása lehetőséget. A program egy üres mezőt ad hozzá. Ha egy meglévő mezőcsoporttal dolgozik, görgessen lefelé a mező beállításához.
Adjon nevet a mezőnek, és állítsa be a típust a következőre: vagy
Edm.ComplexType
Collection(Edm.ComplexType)
.Jelölje ki a jobb szélső három pontot, majd válassza a Mező hozzáadása vagy Az almező hozzáadása lehetőséget, majd rendeljen hozzá attribútumokat.
Összetett gyűjteménykorlátok
Az indexelés során legfeljebb 3000 elem lehet egyetlen dokumentum összes összetett gyűjteményében. Az összetett gyűjtemény egyik eleme ennek a gyűjteménynek a tagja. A Szobák (a szállodai példa egyetlen összetett gyűjteménye) esetében minden szoba elem. A fenti példában, ha a "Stay-Kay City Hotel" 500 szobával rendelkezne, a szálloda dokumentuma 500 szobaelemből állna. Beágyazott összetett gyűjtemények esetén a külső (szülő) elem mellett az egyes beágyazott elemek is megszámlálhatók.
Ez a korlát csak összetett gyűjteményekre vonatkozik, és nem összetett típusokra (például Cím) vagy sztringgyűjteményekre (például Címkék).
Összetett mezők frissítése
A mezőkre általában érvényes összes újraindexelési szabály továbbra is az összetett mezőkre vonatkozik. Egy új mező összetett típushoz való hozzáadása nem igényel index-újraépítést, de a legtöbb más módosításhoz újra kell építeni.
A definíció szerkezeti frissítései
Új almezőket bármikor hozzáadhat egy összetett mezőhöz anélkül, hogy index-újraépítésre van szükség. Például a "ZipCode" Address
vagy a "Amenities" Rooms
hozzáadása engedélyezett, ugyanúgy, mint egy felső szintű mező hozzáadása egy indexhez. A meglévő dokumentumok null értékkel rendelkeznek az új mezőkhöz, amíg az adatok frissítésével explicit módon nem tölti ki ezeket a mezőket.
Figyelje meg, hogy egy összetett típuson belül minden almező rendelkezik egy típussal, és attribútumokkal rendelkezhet, ahogyan a legfelső szintű mezők is.
Adatfrissítések
Az index meglévő dokumentumainak frissítése a upload
művelettel ugyanúgy működik, mint az összetett és egyszerű mezők esetében: minden mező lecserélődik. Azonban merge
(vagy mergeOrUpload
ha egy meglévő dokumentumra alkalmazva) nem működik minden mezőnél. merge
Pontosabban nem támogatja a gyűjtemény elemeinek egyesítését. Ez a korlátozás primitív típusú és összetett gyűjteményekre vonatkozik. A gyűjtemény frissítéséhez le kell kérnie a teljes gyűjteményi értéket, módosítania kell, majd be kell foglalnia az új gyűjteményt az Index API-kérelembe.
Összetett mezők keresése szöveges lekérdezésekben
A szabad formátumú keresési kifejezések a várt módon működnek az összetett típusok esetében. Ha egy dokumentum bármely kereshető mezője vagy almezője megegyezik, akkor maga a dokumentum egyezés.
A lekérdezések árnyaltabbak lesznek, ha több kifejezéssel és operátorral rendelkezik, és egyes kifejezésekben mezőnevek vannak megadva, ahogyan az a Lucene szintaxisban lehetséges. Ez a lekérdezés például a Cím mező két almezőjéhez próbál egyezni a "Portland" és az "OR" kifejezésekkel:
search=Address/City:Portland AND Address/State:OR
Az ilyen lekérdezések a szűrőkkel ellentétben nem számítanak teljes szöveges keresésnek. A szűrőkben az összetett gyűjtemény almezőire vonatkozó lekérdezések a tartományváltozók használatával vannak korrelálva.any
all
A fenti Lucene-lekérdezés "Portland, Maine" és "Portland, Oregon" dokumentumokat, valamint Oregon többi városát is visszaadja. Ez azért történik, mert az egyes záradékok a teljes dokumentumban a mező összes értékére vonatkoznak, így az "aktuális aldokumentum" fogalma nem létezik. Erről további információt az Azure AI Search OData-gyűjteményszűrőinek ismertetése című témakörben talál.
Összetett mezők keresése RAG-lekérdezésekben
A RAG-minta továbbítja a keresési eredményeket egy csevegőmodellnek a generatív AI és a beszélgetési keresés érdekében. Alapértelmezés szerint az LLM-nek átadott keresési eredmények egy lapított sorkészletek. Ha azonban az index összetett típusokból áll, a lekérdezés ezeket a mezőket is megadhatja, ha először JSON-ra konvertálja a keresési eredményeket, majd átadja a JSON-t az LLM-nek.
Egy részleges példa a technikát szemlélteti:
- Adja meg a kívánt mezőket a parancssorban vagy a lekérdezésben
- Győződjön meg arról, hogy a mezők kereshetők és lekérdezhetők az indexben
- A keresési eredmények mezőinek kiválasztása
- Az eredmények formázása JSON-ként
- A csevegés befejezésére vonatkozó kérés elküldése a modellszolgáltatónak
import json
# Query is the question being asked. It's sent to the search engine and the LLM.
query="Can you recommend a few hotels that offer complimentary breakfast? Tell me their description, address, tags, and the rate for one room they have which sleep 4 people."
# Set up the search results and the chat thread.
# Retrieve the selected fields from the search index related to the question.
selected_fields = ["HotelName","Description","Address","Rooms","Tags"]
search_results = search_client.search(
search_text=query,
top=5,
select=selected_fields,
query_type="semantic"
)
sources_filtered = [{field: result[field] for field in selected_fields} for result in search_results]
sources_formatted = "\n".join([json.dumps(source) for source in sources_filtered])
response = openai_client.chat.completions.create(
messages=[
{
"role": "user",
"content": GROUNDED_PROMPT.format(query=query, sources=sources_formatted)
}
],
model=AZURE_DEPLOYMENT_MODEL
)
print(response.choices[0].message.content)
A végpontok közötti példaért tekintse meg a gyorsútmutatót: Generatív keresés (RAG) az Azure AI Searchből származó földelési adatokkal.
Összetett mezők kijelölése
A $select
paraméter a keresési eredményekben visszaadott mezők kiválasztására szolgál. Ha ezt a paramétert egy összetett mező adott almezőinek kiválasztásához szeretné használni, adja meg a szülőmezőt és az almezőt perjellel (/
perjellel) elválasztva.
$select=HotelName, Address/City, Rooms/BaseRate
A mezőket lekérdezhetőként kell megjelölni az indexben, ha azt szeretné, hogy a keresési eredményekben szerepeljenek. Utasításban $select
csak lekérésesként megjelölt mezők használhatók.
Összetett mezők szűrése, aspektusa és rendezése
A szűréshez és a mezőalapú keresésekhez használt OData-elérési út szintaxisa a keresési kérelmek mezőinek szűrésére, rendezésére és kijelölésére is használható. Összetett típusok esetén olyan szabályok vonatkoznak, amelyek szabályozzák, hogy mely almezők jelölhetők rendezhetőként vagy facetableként. Ezekről a szabályokról további információt az Index API létrehozása referenciában talál.
Arculati almezők
Az almezők csak akkor jelölhetők facetable-ként, ha típus Edm.GeographyPoint
Collection(Edm.GeographyPoint)
vagy .
Az eredményben visszaadott dokumentumszámokat a szülődokumentum (szálloda) számítja ki, nem pedig egy összetett gyűjtemény (szobák) aldokumentumaira. Tegyük fel például, hogy egy szálloda 20 "suite" típusú szobával rendelkezik. Tekintettel erre a szempontra facet=Rooms/Type
, a aspektusok száma a szálloda számára egy, nem pedig a szobák esetében 20.
Összetett mezők rendezése
A rendezési műveletek a dokumentumokra (szállodákra) és nem aldokumentumokra (Szobákra) vonatkoznak. Ha összetett típusú gyűjteménysel rendelkezik, például a Szobákkal, fontos felismerni, hogy egyáltalán nem lehet rendezni a szobákat. Valójában nem rendezhet gyűjteményeket.
A rendezési műveletek akkor működnek, ha a mezők dokumentumonként egyetlen értékkel rendelkeznek, legyen szó egyszerű mezőről vagy összetett típusú almezőről. Például lehet rendezhető, Address/City
mert szállodánként csak egy cím van, ezért $orderby=Address/City
a szállodákat város szerint rendezi.
Szűrés összetett mezőkön
Egy szűrőkifejezésben egy összetett mező almezőire hivatkozhat. Csak használja ugyanazt az OData-elérési út szintaxist , amely a mezők arculati, rendezési és kijelölési módját használja. Az alábbi szűrő például az összes kanadai szállodát visszaadja:
$filter=Address/Country eq 'Canada'
Összetett gyűjteménymezőkre való szűréshez használhat lambda kifejezést és all
any
operátorokat. Ebben az esetben a lambda kifejezés tartományváltozója egy almezőkkel rendelkező objektum. Ezekre az almezőkre a standard OData-elérési út szintaxisával hivatkozhat. Az alábbi szűrő például az összes olyan szállodát visszaadja, amelynek legalább egy deluxe szobája van, és az összes nem szálló szobája:
$filter=Rooms/any(room: room/Type eq 'Deluxe Room') and Rooms/all(room: not room/SmokingAllowed)
A legfelső szintű egyszerű mezőkhöz hasonlóan az összetett mezők egyszerű almezői csak akkor vehetők fel a szűrőkbe, ha az indexdefinícióban a szűrhető attribútum van beállítva true
. További információkért tekintse meg az Index API létrehozása referenciát.
Áthidaló megoldás az összetett gyűjteménykorláthoz
Ne feledje, hogy az Azure AI Search dokumentumonként 3000 objektumra korlátozza a gyűjtemény összetett objektumait. Ha túllépi ezt a korlátot, a következő üzenet jelenik meg:
A collection in your document exceeds the maximum elements across all complex collections limit.
The document with key '1052' has '4303' objects in collections (JSON arrays).
At most '3000' objects are allowed to be in collections across the entire document.
Remove objects from collections and try indexing the document again."
Ha több mint 3000 elemre van szüksége, az értékeket elválasztó csövet (|
) vagy bármilyen típusú elválasztót használhat az értékek elválasztásához, összefűzéséhez és elválasztott sztringként való tárolásához. A tömbben tárolt sztringek száma nincs korlátozva. Az összetett értékek sztringként való tárolása meghaladja az összetett gyűjtemény korlátozását.
A szemléltetés érdekében tegyük fel, hogy több mint 3000 elemből áll egy "searchScope
" tömb:
"searchScope": [
{
"countryCode": "FRA",
"productCode": 1234,
"categoryCode": "C100"
},
{
"countryCode": "USA",
"productCode": 1235,
"categoryCode": "C200"
}
. . .
]
Az értékek tagolt sztringként való tárolásának kerülő megoldása a következőképpen nézhet ki:
"searchScope": [
"|FRA|1234|C100|",
"|FRA|*|*|",
"|*|1234|*|",
"|*|*|C100|",
"|FRA|*|C100|",
"|*|1234|C100|"
]
Az összes keresési változat tárolása a tagolt sztringben hasznos lehet olyan keresési forgatókönyvekben, ahol olyan elemeket szeretne keresni, amelyek csak "FRA" vagy "1234" vagy más kombinációval rendelkeznek a tömbön belül.
Az alábbiakban egy C# szűrőformázási kódrészletet talál, amely kereshető sztringekké alakítja a bemeneteket:
foreach (var filterItem in filterCombinations)
{
var formattedCondition = $"searchScope/any(s: s eq '{filterItem}')";
combFilter.Append(combFilter.Length > 0 ? " or (" + formattedCondition + ")" : "(" + formattedCondition + ")");
}
Az alábbi lista bemeneteket és keresési sztringeket (kimeneteket) tartalmaz egymás mellett:
A "FRA" megyei kód és az "1234" termékkód esetében a formázott kimenet a
|FRA|1234|*|
.Az "1234" termékkód esetében a formázott kimenet a következő
|*|1234|*|
.A "C100" kategóriakód esetén a formázott kimenet a következő
|*|*|C100|
.
Csak akkor adja meg a helyettesítő karaktert (*
), ha a sztringtömb megkerülő megoldását implementálja. Ellenkező esetben, ha összetett típust használ, a szűrő az alábbi példához hasonlóan nézhet ki:
var countryFilter = $"searchScope/any(ss: search.in(countryCode ,'FRA'))";
var catgFilter = $"searchScope/any(ss: search.in(categoryCode ,'C100'))";
var combinedCountryCategoryFilter = "(" + countryFilter + " and " + catgFilter + ")";
Ha implementálja a kerülő megoldást, mindenképpen tesztelje a mértékeket.
Következő lépések
Próbálja ki a Hotels adatkészletet az Adatok importálása varázslóban. Az adatok eléréséhez szüksége van az azure Cosmos DB kapcsolati információira az olvasási dokumentumban.
Ezen információk birtokában a varázsló első lépése egy új Azure Cosmos DB-adatforrás létrehozása. A varázslóban tovább haladva, amikor a célindexlapra ér, egy összetett típusú index jelenik meg. Hozza létre és töltse be ezt az indexet, majd hajtson végre lekérdezéseket az új struktúra megértéséhez.