Modellera relations-SQL-data för import och indexering i Azure AI Search
Azure AI Search accepterar en platt raduppsättning som indata till indexeringspipelinen. Om dina källdata kommer från anslutna tabeller i en SQL Server-relationsdatabas förklarar den här artikeln hur du konstruerar resultatuppsättningen och hur du modellerar en överordnad-underordnad relation i ett Azure AI Search-index.
Som en illustration refererar vi till en hypotetisk hotelldatabas, baserad på demodata. Anta att databasen består av en Hotels$
tabell med 50 hotell och en Rooms$
tabell med rum av olika typer, priser och bekvämligheter, för totalt 750 rum. Det finns en en-till-många-relation mellan tabellerna. I vår metod tillhandahåller en vy frågan som returnerar 50 rader, en rad per hotell, med tillhörande rumsinformation inbäddad i varje rad.
Problemet med avnormaliserade data
En av utmaningarna med att arbeta med en-till-många-relationer är att standardfrågor som bygger på anslutna tabeller returnerar avnormaliserade data, vilket inte fungerar bra i ett Azure AI Search-scenario. Tänk dig följande exempel som ansluter till hotell och rum.
SELECT * FROM Hotels$
INNER JOIN Rooms$
ON Rooms$.HotelID = Hotels$.HotelID
Resultat från den här frågan returnerar alla hotellfält, följt av alla rumsfält, där preliminär hotellinformation upprepas för varje rumsvärde.
Även om den här frågan lyckas på ytan (vilket ger alla data i en platt raduppsättning), misslyckas den med att leverera rätt dokumentstruktur för den förväntade sökupplevelsen. Under indexeringen skapar Azure AI Search ett sökdokument för varje rad som matas in. Om dina sökdokument såg ut som ovanstående resultat skulle du ha uppfattat dubbletter - sju separata dokument enbart för Old Century Hotel. En fråga om "hotell i Florida" skulle returnera sju resultat för bara Old Century Hotel, vilket pressade andra relevanta hotell djupt in i sökresultaten.
För att få den förväntade upplevelsen av ett dokument per hotell bör du ange en raduppsättning på rätt kornighet, men med fullständig information. I den här artikeln förklaras hur.
Definiera en fråga som returnerar inbäddad JSON
För att leverera den förväntade sökupplevelsen bör datauppsättningen bestå av en rad för varje sökdokument i Azure AI Search. I vårt exempel vill vi ha en rad för varje hotell, men vi vill också att våra användare ska kunna söka på andra rumsrelaterade fält som de bryr sig om, till exempel nattpris, storlek och antal bäddar, eller en utsikt över stranden, som alla ingår i en rumsdetalj.
Lösningen är att avbilda rumsinformationen som kapslad JSON och sedan infoga JSON-strukturen i ett fält i en vy, som visas i det andra steget.
Anta att du har två anslutna tabeller,
Hotels$
ochRooms$
, som innehåller information för 50 hotell och 750 rum och är anslutna till fältet HotelID. Individuellt innehåller dessa tabeller 50 hotell och 750 relaterade rum.CREATE TABLE [dbo].[Hotels$]( [HotelID] [nchar](10) NOT NULL, [HotelName] [nvarchar](255) NULL, [Description] [nvarchar](max) NULL, [Description_fr] [nvarchar](max) NULL, [Category] [nvarchar](255) NULL, [Tags] [nvarchar](255) NULL, [ParkingIncluded] [float] NULL, [SmokingAllowed] [float] NULL, [LastRenovationDate] [smalldatetime] NULL, [Rating] [float] NULL, [StreetAddress] [nvarchar](255) NULL, [City] [nvarchar](255) NULL, [State] [nvarchar](255) NULL, [ZipCode] [nvarchar](255) NULL, [GeoCoordinates] [nvarchar](255) NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO CREATE TABLE [dbo].[Rooms$]( [HotelID] [nchar](10) NULL, [Description] [nvarchar](255) NULL, [Description_fr] [nvarchar](255) NULL, [Type] [nvarchar](255) NULL, [BaseRate] [float] NULL, [BedOptions] [nvarchar](255) NULL, [SleepsCount] [float] NULL, [SmokingAllowed] [float] NULL, [Tags] [nvarchar](255) NULL ) ON [PRIMARY] GO
Skapa en vy som består av alla fält i den överordnade tabellen (
SELECT * from dbo.Hotels$
), med ett nytt rumsfält som innehåller utdata från en kapslad fråga. En FOR JSON AUTO-sats förSELECT * from dbo.Rooms$
strukturerar utdata som JSON.CREATE VIEW [dbo].[HotelRooms] AS SELECT *, (SELECT * FROM dbo.Rooms$ WHERE dbo.Rooms$.HotelID = dbo.Hotels$.HotelID FOR JSON AUTO) AS Rooms FROM dbo.Hotels$ GO
Följande skärmbild visar den resulterande vyn med fältet Rum nvarchar längst ned. Fältet Rum finns bara i vyn Hotellrum.
Kör
SELECT * FROM dbo.HotelRooms
för att hämta raduppsättningen. Den här frågan returnerar 50 rader, en per hotell, med tillhörande rumsinformation som en JSON-samling.
Den här raduppsättningen är nu redo för import till Azure AI Search.
Kommentar
Den här metoden förutsätter att inbäddad JSON ligger under de maximala kolumnstorleksgränserna för SQL Server.
Använda en komplex samling för "många"-sidan av en en-till-många-relation
På Azure AI Search-sidan skapar du ett indexschema som modellerar en-till-många-relationen med kapslad JSON. Resultatuppsättningen som du skapade i föregående avsnitt motsvarar vanligtvis indexschemat som anges härnäst (vi skär några fält för korthet).
Följande exempel liknar exemplet i Modellera komplexa datatyper. Rumsstrukturen, som har varit i fokus för den här artikeln, finns i fältsamlingen för ett index med namnet hotels. Det här exemplet visar också en komplex typ för Adress, som skiljer sig från Rum eftersom den består av en fast uppsättning objekt, i motsats till det flera godtyckliga antalet objekt som tillåts i en samling.
{
"name": "hotels",
"fields": [
{ "name": "HotelId", "type": "Edm.String", "key": true, "filterable": true },
{ "name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false },
{ "name": "Description", "type": "Edm.String", "searchable": true, "analyzer": "en.lucene" },
{ "name": "Description_fr", "type": "Edm.String", "searchable": true, "analyzer": "fr.lucene" },
{ "name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "facetable": true },
{ "name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "facetable": true },
{ "name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "facetable": true },
{ "name": "Address", "type": "Edm.ComplexType",
"fields": [
{ "name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true },
{ "name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true },
{ "name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }
]
},
{ "name": "Rooms", "type": "Collection(Edm.ComplexType)",
"fields": [
{ "name": "Description", "type": "Edm.String", "searchable": true, "analyzer": "en.lucene" },
{ "name": "Description_fr", "type": "Edm.String", "searchable": true, "analyzer": "fr.lucene" },
{ "name": "Type", "type": "Edm.String", "searchable": true },
{ "name": "BaseRate", "type": "Edm.Double", "filterable": true, "facetable": true },
{ "name": "BedOptions", "type": "Edm.String", "searchable": true, "filterable": true, "facetable": false },
{ "name": "SleepsCount", "type": "Edm.Int32", "filterable": true, "facetable": true },
{ "name": "SmokingAllowed", "type": "Edm.Boolean", "filterable": true, "facetable": false},
{ "name": "Tags", "type": "Edm.Collection", "searchable": true }
]
}
]
}
Med tanke på den tidigare resultatuppsättningen och indexschemat ovan har du alla nödvändiga komponenter för en lyckad indexeringsåtgärd. Den utplattade datauppsättningen uppfyller indexeringskraven men bevarar ändå information. I Azure AI Search-indexet hamnar sökresultaten enkelt i hotellbaserade entiteter, samtidigt som kontexten för enskilda rum och deras attribut bevaras.
Fasetteringsbeteende på komplexa underfält av typen
Fält som har en överordnad, till exempel fälten under Adress och Rum, kallas underfält. Även om du kan tilldela ett "facetable"-attribut till ett underfält, är antalet fasetter alltid för huvuddokumentet.
För komplexa typer som Adress, där det bara finns en "Adress/stad" eller "Adress/tillståndProvince" i dokumentet, fungerar fasetteringsbeteendet som förväntat. Men när det gäller Rum, där det finns flera underdokument för varje huvuddokument, kan antalet fasetter vara vilseledande.
Som anges i Modellkomplextyper: "De dokumentantal som returneras i fasetteringsresultatet beräknas för det överordnade dokumentet (ett hotell), inte underdokumenten i en komplex samling (rum). Anta till exempel att ett hotell har 20 rum av typen "suite". Med tanke på den här aspektparametern facet=Rum/typ är antalet fasetter ett för hotellet, inte 20 för rummen."
Nästa steg
Med din egen datauppsättning kan du använda guiden Importera data för att skapa och läsa in indexet. Guiden identifierar den inbäddade JSON-samlingen, till exempel den som finns i Rum, och härleder ett indexschema som innehåller en komplex typsamling.
Prova följande snabbstart för att lära dig de grundläggande stegen i guiden Importera data.