Azure AI 검색에서 복잡한 데이터 형식 모델링

Azure AI 검색 인덱스를 채우는 데 사용되는 외부 데이터 세트는 다양한 형태로 제공될 수 있습니다. 계층적 또는 중첩된 하위 구조체를 포함하는 경우도 있습니다. 예제에는 한 고객에 여러 주소, 단일 SKU에 여러 색과 크기, 한 권의 책에 여러 저자 등이 포함될 수 있습니다. 모델링 용어에서 complex, compound, composite 또는 aggregate 데이터 형식이라고 하는 구조를 볼 수 있습니다. 이 개념에 대해 Azure AI 검색이 사용하는 용어는 복합 형식입니다. Azure AI 검색에서 복합 형식은 복합 필드를 사용하여 모델링됩니다. 복합 필드는 다른 복합 형식을 포함하여 모든 데이터 형식일 수 있는 자식(하위 필드)을 포함하는 필드입니다. 이는 프로그래밍 언어에서 구조화된 데이터 형식과 비슷한 방식으로 작동합니다.

복합 필드는 데이터 형식에 따라 문서의 단일 개체 또는 개체의 배열을 나타냅니다. Edm.ComplexType 형식의 필드는 단일 개체를 나타내고, Collection(Edm.ComplexType) 형식의 필드는 개체의 배열을 나타냅니다.

Azure AI 검색은 기본적으로 복합 형식과 컬렉션을 지원합니다. 이러한 형식을 사용하면 Azure AI 검색 인덱스에서 거의 모든 JSON 구조를 모델링할 수 있습니다. 이전 버전의 Azure AI 검색 API에서는 일반 행 집합만 가져올 수 있었습니다. 최신 버전에서는 이제 인덱스가 원본 데이터와 더 밀접하게 일치합니다. 즉, 원본 데이터에 복합 형식이 있는 경우 인덱스에도 복합 형식이 있을 수 있습니다.

시작하려면 Azure Portal의 데이터 가져오기 마법사에서 로드할 수 있는 호텔 데이터 세트를 권장합니다. 마법사는 원본의 복합 형식을 검색하고 검색된 구조를 기반으로 인덱스 스키마를 제안합니다.

참고 항목

복합 형식에 대한 지원은 일반적으로부터 api-version=2019-05-06부터 사용할 수 있습니다.

검색 솔루션이 컬렉션의 일반 데이터 세트에 대한 이전 해결 방법을 기반으로 하는 경우 최신 API 버전에서 지원되는 복합 형식을 포함하도록 인덱스를 변경해야 합니다. API 버전을 업그레이드하는 방법에 대한 자세한 내용은 최신 REST API 버전으로 업그레이드 또는 최신 .NET SDK 버전으로 업그레이드를 참조하세요.

복합 구조의 예제

다음 JSON 문서는 간단한 필드와 복합 필드로 구성됩니다. AddressRooms와 같은 복잡한 필드에는 하위 필드가 있습니다. Address에는 문서의 단일 개체이므로 해당 하위 필드에 대한 단일 값 세트가 있습니다. 반면, Rooms에는 컬렉션의 각 개체에 대해 하나씩, 하위 필드에 대한 값 세트가 여러 개 있습니다.

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

복합 형식 인덱싱

인덱싱 중에 단일 문서 내의 모든 복합 컬렉션에서 최대 3000개의 요소를 가질 수 있습니다. 복합 컬렉션의 요소는 해당 컬렉션의 멤버이므로 객실의 경우(호텔 예제의 유일한 복합 컬렉션) 각 객실은 요소입니다. 위의 예제에서 “Secret Point Motel”에 500개의 객실이 있으면 호텔 문서에는 500개 객실 요소가 있습니다. 중첩된 복합 컬렉션의 경우 외부(부모) 요소 외에도 각 중첩된 요소가 계산됩니다.

이 제한은 복합 형식(예: 주소) 또는 문자열 컬렉션(예: 태그)이 아닌 복합 컬렉션에만 적용됩니다.

복합 필드 만들기

모든 인덱스 정의와 마찬가지로, 포털, REST API 또는 .NET SDK를 사용하여 복합 형식을 포함하는 스키마를 만들 수 있습니다.

다른 Azure SDK는 Python, JavaJavaScript에서 샘플을 제공합니다.

  1. Azure Portal에 로그인합니다.

  2. 검색 서비스 개요 페이지에서 인덱스 탭을 선택합니다.

  3. 기존 인덱스를 열거나 새 인덱스를 만듭니다.

  4. 필드 탭을 선택한 다음, 필드 추가를 선택합니다. 빈 필드가 추가됩니다. 기존 필드 컬렉션으로 작업하는 경우 아래로 스크롤하여 필드를 설정합니다.

  5. 필드에 이름을 지정하고 형식을 Edm.ComplexType 또는 Collection(Edm.ComplexType)으로 설정합니다.

  6. 맨 오른쪽에서 타원을 선택한 다음, 필드 추가 또는 하위 필드 추가를 선택한 다음, 특성을 할당합니다.

복합 필드 업데이트

일반적으로 필드에 적용되는 모든 다시 인덱스 규칙은 복합 필드에도 적용됩니다. 여기에서 몇 가지 주요 규칙을 재작성하고, 복합 형식에 필드를 추가하는 경우 인덱스를 다시 빌드할 필요가 없지만 대부분의 수정 작업이 수행됩니다.

정의에 대한 구조적 업데이트

인덱스를 다시 빌드할 필요 없이 언제든지 복합 필드에 새 하위 필드를 추가할 수 있습니다. 예를 들어 인덱스에 최상위 필드를 추가하는 것처럼 Address에 “ZipCode”를 또는 Rooms에 “Amenities”를 추가하는 것이 허용됩니다. 기존 문서에는 데이터를 업데이트하여 명시적으로 필드를 채울 때까지 새 필드에 대한 null 값이 있습니다.

복합 형식 내에서 각 하위 필드에는 형식이 있으며 최상위 필드와 마찬가지로 특성도 가질 수 있습니다.

데이터 업데이트

upload 작업을 사용하여 인덱스에서 기존 문서를 업데이트하는 작업은 복합 필드와 단순 필드에 대해 동일한 방식으로 작동합니다. 즉, 모든 필드가 바뀝니다. 그러나 merge(또는 기존 문서에 적용되는 경우 mergeOrUpload)는 모든 필드에서 동일하게 작동하지 않습니다. 특히 merge는 컬렉션 내에서 요소를 병합하는 것을 지원하지 않습니다. 이 제한 사항은 기본 형식의 컬렉션 및 복합 컬렉션에 대해 존재합니다. 컬렉션을 업데이트하려면 전체 컬렉션 값을 검색하고 변경한 다음, 인덱스 API 요청에 새 컬렉션을 포함해야 합니다.

복합 필드 검색

자유 형식 검색 식은 복합 형식에서 예상대로 작동합니다. 문서에서 검색 가능한 필드 또는 하위 필드가 일치하는 경우 문서 자체는 일치 항목입니다.

Lucene 구문에서 가능한 한 여러 용어와 연산자가 있고 일부 용어에 필드 이름이 지정된 경우 쿼리에 더 많은 미묘한 차이가 발생합니다. 예를 들어 이 쿼리는 Address 필드의 두 하위 필드에 대해 두 개의 용어 “Portland” 및 “OR”를 일치시키려고 합니다.

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

이와 같은 쿼리는 필터와 달리 전체 텍스트 검색과는 상관 관계가 없습니다. 필터에서 복합 컬렉션의 하위 필드에 대한 쿼리는 any 또는 all의 범위 변수를 사용하여 상호 관련됩니다. 위의 Lucene 쿼리는 오리건의 다른 도시와 함께 “Portland, Maine(메인 주 포틀랜드)”와 “Portland, Oregon(오리건 주 포틀랜드)”를 모두 포함하는 문서를 반환합니다. 이는 각 절이 전체 문서에 있는 해당 필드의 모든 값에 적용되므로 발생합니다. 따라서 “현재 하위 문서”의 개념이 없다는 것입니다. 이에 대한 자세한 내용은 Azure AI 검색의 OData 컬렉션 필터 이해를 참조하세요.

복합 필드 선택

$select 매개 변수는 검색 결과에서 반환되는 필드를 선택하는 데 사용됩니다. 이 매개 변수를 사용하여 복합 필드의 특정 하위 필드를 선택하려면 슬래시(/)로 구분된 부모 필드와 하위 필드를 포함합니다.

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

필드는 검색 결과에서 원하는 경우 인덱스에서 조회 가능으로 표시되어야 합니다. 조회 가능으로 표시된 필드만 $select 문에서 사용할 수 있습니다.

필터, 패싯 및 정렬 복합 필드

필터링 및 필드 지정 검색에 사용되는 것과 동일한 OData 경로 구문도 검색 요청에서 필드를 패싯, 정렬 및 선택하는 데 사용할 수 있습니다. 복합 형식의 경우 정렬 가능 또는 패싯 가능으로 표시할 수 있는 하위 필드를 제어하는 규칙이 적용됩니다. 이러한 규칙에 대한 자세한 내용은 인덱스 API 참조 만들기를 참조하세요.

패싯 하위 필드

Edm.GeographyPoint 또는 Collection(Edm.GeographyPoint) 형식이 아닌 경우 모든 하위 필드는 패싯 가능으로 표시될 수 있습니다.

패싯 결과에서 반환되는 문서 개수는 부모 문서(호텔)에 대해 계산되며, 이는 복합 컬렉션(객실)의 하위 문서가 아닙니다. 예를 들어 호텔에 “suite” 형식의 객실이 20개 있다고 가정해 보겠습니다. 이 패싯 매개 변수 facet=Rooms/Type이 주어지면 패싯 개수는 객실에 대해 20개가 아니라 호텔에 대해 1개입니다.

복합 필드 정렬

정렬 작업은 하위 문서(객실)가 아닌 문서(호텔)에 적용됩니다. 객실과 같은 복합 형식 컬렉션을 사용할 경우에는 객실을 정렬할 수 없다는 점을 알아야 합니다. 실제로 컬렉션을 정렬할 수 없습니다.

정렬 작업은 필드가 단순 필드이든 복합 형식의 하위 필드이든 상관없이 필드에 문서당 단일 값이 있으면 작동합니다. 예를 들어, 호텔당 주소가 하나뿐이므로 Address/City는 정렬 가능하므로 $orderby=Address/City는 호텔을 도시별로 정렬합니다.

복합 필드에서 필터링

필터 식에서 복합 필드의 하위 필드를 참조할 수 있습니다. 패싯, 정렬 및 필드 선택에 사용되는 것과 동일한 OData 경로 구문을 사용하면 됩니다. 예를 들어, 다음 필터는 캐나다의 모든 호텔을 반환합니다.

$filter=Address/Country eq 'Canada'

복합 컬렉션 필드를 필터링하기 위해 anyall 연산자람다 식을 사용할 수 있습니다. 이 경우 람다 식의 범위 변수는 하위 필드가 있는 개체입니다. 표준 OData 경로 구문을 사용하여 해당 하위 필드를 참조할 수 있습니다. 예를 들어, 다음 필터는 디럭스룸이 하나 이상 있는 모든 호텔과 모두 금연실을 반환합니다.

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

최상위 단순 필드와 마찬가지로, 인덱스 정의에서 필터링 가능 특성이 true로 설정된 경우에만 복합 필드의 단순 하위 필드를 필터에 포함할 수 있습니다. 자세한 내용은 인덱스 API 참조 만들기를 참조하세요.

Azure Search에는 단일 문서에서 컬렉션의 복잡한 개체가 3000을 초과할 수 없다는 제한 사항이 있습니다.

복잡한 컬렉션이 3000 제한을 초과하면 인덱싱하는 동안 사용자에게 아래 오류가 발생합니다.

"문서의 컬렉션이 모든 복합 컬렉션 제한의 최대 요소를 초과합니다. 키 '1052'가 있는 문서에는 컬렉션(JSON 배열)에 '4303' 개체가 있습니다. 최대 '3000' 개체는 전체 문서의 컬렉션에 있을 수 있습니다. 컬렉션에서 개체를 제거하고 문서를 다시 인덱싱해 보세요."

일부 사용 사례에서는 컬렉션에 3000개 이상의 항목을 추가해야 할 수 있습니다. 이러한 사용 사례에서는 파이프(|)하거나 임의의 형태의 구분 기호를 사용하여 값을 구분하고, 연결하고, 구분된 문자열로 저장할 수 있습니다. Azure Search의 배열에 저장된 문자열 수에는 제한이 없습니다. 이러한 복잡한 값을 문자열로 저장하면 제한이 방지됩니다. 고객은 이 해결 방법이 시나리오 요구 사항을 충족하는지 확인해야 합니다.

예를 들어 아래의 "searchScope" 배열에 3000개 이상의 요소가 있는 경우 복합 형식을 사용할 수 없습니다.


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

이러한 복합 값을 구분 기호가 있는 문자열로 저장하면 제한 사항을 방지할 수 있습니다.

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

이러한 분석기를 와일드 카드 저장하는 대신 단어를 | 으로 분할하는 사용자 지정 분석기를 사용하여 스토리지 크기를 줄일 수도 있습니다.

값을 아래와 같이 저장하는 대신 wild카드s로 저장한 이유

|FRA|1234|C100|

는 고객이 제품 및 범주에 관계없이 프랑스 국가가 있는 항목을 검색하려는 검색 시나리오를 수용하기 위한 것입니다. 마찬가지로 고객은 국가 또는 범주에 관계없이 항목에 제품 1234가 있는지 검색해야 할 수 있습니다.

항목을 하나만 저장한 경우

|FRA|1234|C100|

wild카드s가 없으면 사용자가 프랑스에서만 필터링하려는 경우 "searchScope" 배열에 프랑스 조합이 있는지 모르기 때문에 사용자 입력을 "searchScope" 배열과 일치하도록 변환할 수 없습니다.

사용자가 국가별로만 필터링하려는 경우 프랑스라고 가정해 보겠습니다. 사용자 입력을 가져와서 아래와 같이 문자열로 생성합니다.

|FRA|*|*|

그러면 항목 값 배열에서 검색할 때 Azure Search에서 필터링하는 데 사용할 수 있습니다.

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

마찬가지로, 사용자가 프랑스 및 1234 제품 코드를 검색하는 경우 사용자 입력을 받아 아래와 같이 구분된 문자열로 구성하고 검색 배열과 일치합니다.

|FRA|1234|*|

사용자가 1234 제품 코드를 검색하는 경우 사용자 입력을 받아 아래와 같이 구분된 문자열로 구성하고 검색 배열과 일치합니다.

|*|1234|*|

사용자가 C100 범주 코드를 검색하는 경우 사용자 입력을 받아 아래와 같이 구분된 문자열로 구성하고 검색 배열과 일치합니다.

|*|*|C100|

사용자가 프랑스 및 1234 제품 코드 및 C100 범주 코드를 검색하는 경우 사용자 입력을 받아 아래와 같이 구분된 문자열로 구성하고 검색 배열과 일치합니다.

|FRA|1234|C100|

사용자가 목록에 없는 국가를 검색하려고 하면 검색 인덱스로 저장된 구분된 배열 "searchScope"와 일치하지 않으며 결과가 반환되지 않습니다. 예를 들어 사용자는 캐나다 및 제품 코드 1234를 검색합니다. 사용자 검색이 로 변환됩니다.

|CAN|1234|*|

이 항목은 검색 인덱스의 구분된 배열에 있는 항목과 일치하지 않습니다.

위의 디자인 선택에만 이 와일드 카드 항목이 필요합니다. 복잡한 개체로 저장한 경우 아래와 같이 명시적 검색을 수행할 수 있습니다.

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

따라서 복잡한 컬렉션이 Azure Search 제한을 초과하는 경우 복잡한 컬렉션 대신 구분된 문자열로 저장하여 값 조합을 검색해야 하는 요구 사항을 충족할 수 있습니다. 이는 해결 방법 중 하나이며, 고객은 시나리오 요구 사항을 충족하는지 확인해야 합니다.

다음 단계

데이터 가져오기 마법사에서 호텔 데이터 세트를 사용해 봅니다. 데이터에 액세스하려면 추가 정보에 제공된 Azure Cosmos DB 연결 정보가 필요합니다.

이 정보를 사용한 마법사의 첫 번째 단계는 새 Azure Cosmos DB 데이터 원본을 만드는 것입니다. 마법사에서는 더 나아가 대상 인덱스 페이지에 가서 복합 형식이 포함된 인덱스가 표시됩니다. 이 인덱스를 만들고 로드한 다음, 쿼리를 실행하여 새 구조를 파악합니다.