자습서: .NET SDK를 사용하여 Azure SQL 데이터 인덱싱

Azure SQL Database에서 검색 가능한 데이터를 추출하여 Azure AI 검색의 검색 인덱스로 보내는 인덱서를 구성합니다.

이 자습서에서는 C# 및 .NET용 Azure SDK를 사용하여 다음 작업을 수행합니다.

  • Azure SQL Database에 연결하는 데이터 원본 만들기
  • 인덱서 만들기
  • 인덱서를 실행하여 인덱스에 데이터 로드
  • 확인 단계로 인덱스 쿼리

Azure 구독이 아직 없는 경우 시작하기 전에 체험 계정을 만듭니다.

필수 조건

참고 항목

이 자습서에서는 무료 검색 서비스를 사용할 수 있습니다. 무료 계층에서는 인덱스 3개, 인덱서 3개, 데이터 원본 3개로 제한됩니다. 이 자습서에서는 각각을 하나씩 만듭니다. 시작하기 전에 새 리소스를 수용할 수 있는 공간이 서비스에 있는지 확인하세요.

파일 다운로드

이 자습서의 소스 코드는 Azure-Samples/search-dotnet-getting-started GitHub 리포지토리의 DotNetHowToIndexer 폴더에 있습니다.

1 - 서비스 만들기

이 자습서에서는 Azure AI 검색을 인덱싱 및 쿼리에 사용하고 Azure SQL Database를 외부 데이터 원본으로 사용합니다. 가능한 경우 근접성과 관리 효율성을 위해 동일한 지역과 리소스 그룹에 두 서비스를 만듭니다. 실제로 Azure SQL Database는 어느 지역에나 있을 수 있습니다.

Azure SQL Database 시작

이 자습서에서는 데이터베이스를 채우기 위해 샘플 다운로드에 hotels.sql 파일을 제공합니다. Azure AI 검색은 뷰 또는 쿼리에서 생성된 것과 같은 일반 행 집합을 사용합니다. 샘플 솔루션에 있는 SQL 파일은 단일 테이블을 만들고 채웁니다.

기존 Azure SQL Database 리소스가 있는 경우 쿼리 열기 단계부터 시작하여 hotels 테이블을 추가할 수 있습니다.

  1. 빠른 시작: 단일 데이터베이스 만들기의 지침을 사용하여 Azure SQL 데이터베이스를 만듭니다.

    데이터베이스에 대한 서버 구성이 중요합니다.

    • 사용자 이름 및 암호를 지정하라는 메시지를 표시하는 SQL Server 인증 옵션을 선택합니다. 인덱서에서 사용하는 ADO.NET 연결 문자열에 필요합니다.

    • 공용 연결을 선택합니다. 이 자습서를 더 쉽게 완료할 수 있습니다. 프로덕션에는 공용이 권장되지 않으며 자습서가 끝나면 이 리소스를 삭제하는 것이 좋습니다.

    서버 구성 도구 스크린샷

  2. Azure Portal에서 새 리소스로 이동합니다.

  3. 빠른 시작: Azure Portal에서 서버 수준 방화벽 규칙 만들기의 지침을 사용하여 클라이언트의 액세스를 허용하는 방화벽 규칙을 추가합니다. 명령 프롬프트에서 ipconfig를 실행하여 IP 주소를 가져올 수 있습니다.

  4. 쿼리 편집기를 사용하여 샘플 데이터를 로드합니다. 탐색 창에서 쿼리 편집기(미리 보기)를 선택하여 서버 관리자의 사용자 이름과 암호를 입력합니다.

    액세스 거부 오류가 발생하면 오류 메시지에서 클라이언트 IP 주소를 복사하고, 서버의 네트워크 보안 페이지를 열고, 클라이언트의 액세스를 허용하는 인바운드 규칙을 추가합니다.

  5. 쿼리 편집기에서 쿼리 열기를 선택하고, 로컬 컴퓨터에서 hotels.sql 파일의 위치로 이동합니다.

  6. 파일을 선택하고 열기를 선택합니다. 이 스크립트는 다음 스크린샷과 비슷하게 표시됩니다.

    쿼리 편집기 창의 SQL 스크립트 스크린샷.

  7. 실행을 선택하여 쿼리를 실행합니다. 결과 창에서 쿼리 성공 메시지가 3행에 걸쳐 표시됩니다.

  8. 이 테이블에서 행 집합을 반환하려면 확인 단계로 다음 쿼리를 실행할 수 있습니다.

    SELECT * FROM Hotels
    
  9. 데이터베이스에 대한 ADO.NET 연결 문자열을 복사합니다. 설정>연결 문자열 아래에서 아래 예제와 비슷한 ADO.NET 연결 문자열을 복사합니다.

    Server=tcp:<YOUR-DATABASE-NAME>.database.windows.net,1433;Initial Catalog=hotels-db;Persist Security Info=False;User ID=<YOUR-USER-NAME>;Password=<YOUR-PASSWORD>;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
    

이 연결 문자열은 다음 연습에서 환경을 설정하는 데 필요합니다.

다음 구성 요소는 포털에서 만들 수 있는 Azure AI 검색입니다. 이 연습은 체험 계층을 사용하여 완료할 수 있습니다.

API 호출에는 서비스 URL과 액세스 키가 필요합니다. 검색 서비스는 둘 모두를 사용하여 작성되므로 Azure AI 검색을 구독에 추가한 경우 다음 단계에 따라 필요한 정보를 확보하십시오.

  1. Azure Portal에 로그인하고, 검색 서비스 개요 페이지에서 URL을 가져옵니다. 엔드포인트의 예는 다음과 같습니다. https://mydemo.search.windows.net

  2. 설정>에서 서비스에 대한 모든 권한의 관리자 키를 가져옵니다. 교체 가능한 두 개의 관리자 키가 있으며, 하나를 롤오버해야 하는 경우 비즈니스 연속성을 위해 다른 하나가 제공됩니다. 개체 추가, 수정 및 삭제 요청 시 기본 또는 보조 키를 사용할 수 있습니다.

    검색 서비스의 HTTP 엔드포인트 및 액세스 키 위치를 보여 주는 Azure Portal 페이지의 스크린샷.

2 - 환경 설정

  1. Visual Studio를 시작하고 DotNetHowToIndexers.sln을 엽니다.

  2. 솔루션 탐색기에서 appsettings.json을 열고 연결 정보를 제공합니다.

  3. SearchServiceEndPoint의 경우 서비스 개요 페이지의 전체 URL이 “https://my-demo-service.search.windows.net"”이면 제공할 값은 해당 URL입니다.

  4. AzureSqlConnectionString의 경우, 문자열 형식은 다음과 유사합니다. "Server=tcp:<your-database-name>.database.windows.net,1433;Initial Catalog=hotels-db;Persist Security Info=False;User ID=<your-user-name>;Password=<your-password>;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"

    {
      "SearchServiceEndPoint": "<placeholder-search-full-url>",
      "SearchServiceAdminApiKey": "<placeholder-admin-key-for-search-service>",
      "AzureSqlConnectionString": "<placeholder-ADO.NET-connection-string",
    }
    
  5. SQL 연결 문자열의 사용자 암호를 유효한 암호로 바꿉니다. 데이터베이스와 사용자 이름은 복사되지만 암호는 수동으로 입력해야 합니다.

3 - 파이프라인 만들기

인덱서에는 데이터 원본 개체와 인덱스가 필요합니다. 관련 코드는 다음 두 파일에 있습니다.

  • hotel.cs - 인덱스를 정의하는 스키마가 포함되어 있습니다.

  • Program.cs - 서비스에서 구조를 만들고 관리하는 함수가 포함되어 있습니다.

hotel.cs에서

인덱스 스키마는 다음과 같은 HotelName의 필드 정의에 표시된 대로 필드가 전체 텍스트 검색 가능, 필터링 가능, 정렬 가능한지 등 허용되는 작업을 지정하는 속성을 비롯한 필드 컬렉션을 정의합니다. SearchableField는 정의에 따라 전체 텍스트 검색이 가능합니다. 다른 특성은 명시적으로 할당됩니다.

. . . 
[SearchableField(IsFilterable = true, IsSortable = true)]
[JsonPropertyName("hotelName")]
public string HotelName { get; set; }
. . .

스키마는 점수 매기기, 사용자 지정 분석기 및 다른 구문을 향상시키기 위해 점수 매기기 프로필을 비롯한 다른 요소를 포함할 수도 있습니다. 그러나 목적상 스키마는 밀도가 낮게 정의되어 샘플 데이터 세트에서 발견되는 필드를 구성합니다.

Program.cs에서

기본 프로그램에는 인덱서 클라이언트, 인덱스, 데이터 원본 및 인덱서를 만드는 논리가 포함되어 있습니다. 코드는 이 프로그램을 여러 번 실행한다는 가정 하에서 동일한 이름의 기존 리소스를 확인하고 삭제합니다.

데이터 원본 개체는 Azure SQL의 기본 제공 변경 내용 검색 기능을 활용하기 위한 부분 또는 증분 인덱싱을 포함하여 Azure SQL Database 리소스에 한정된 설정을 사용하여 구성됩니다. Azure SQL의 원본 데모 호텔 데이터베이스에는 IsDeleted라는 "일시 삭제" 열이 있습니다. 데이터베이스에서 이 열을 true로 설정하면 인덱서가 Azure AI 검색 인덱스에서 해당 문서를 제거합니다.

Console.WriteLine("Creating data source...");

var dataSource =
      new SearchIndexerDataSourceConnection(
         "hotels-sql-ds",
         SearchIndexerDataSourceType.AzureSql,
         configuration["AzureSQLConnectionString"],
         new SearchIndexerDataContainer("hotels"));

indexerClient.CreateOrUpdateDataSourceConnection(dataSource);

인덱서 개체는 플랫폼의 제약을 받지 않으므로 원본에 관계없이 구성, 일정 예약 및 호출이 동일합니다. 이 예제 인덱서는 인덱서 기록을 지우는 초기화 옵션인 일정을 포함하고 있으며, 즉시 인덱서를 만들고 실행하는 메서드를 호출합니다. 인덱서를 만들거나 업데이트하려면 CreateOrUpdateIndexerAsync를 사용합니다.

Console.WriteLine("Creating Azure SQL indexer...");

var schedule = new IndexingSchedule(TimeSpan.FromDays(1))
{
      StartTime = DateTimeOffset.Now
};

var parameters = new IndexingParameters()
{
      BatchSize = 100,
      MaxFailedItems = 0,
      MaxFailedItemsPerBatch = 0
};

// Indexer declarations require a data source and search index.
// Common optional properties include a schedule, parameters, and field mappings
// The field mappings below are redundant due to how the Hotel class is defined, but 
// we included them anyway to show the syntax 
var indexer = new SearchIndexer("hotels-sql-idxr", dataSource.Name, searchIndex.Name)
{
      Description = "Data indexer",
      Schedule = schedule,
      Parameters = parameters,
      FieldMappings =
      {
         new FieldMapping("_id") {TargetFieldName = "HotelId"},
         new FieldMapping("Amenities") {TargetFieldName = "Tags"}
      }
};

await indexerClient.CreateOrUpdateIndexerAsync(indexer);

인덱서 실행은 일반적으로 예약되어 있지만 개발 중에 RunIndexerAsync를 사용하여 인덱서를 즉시 실행할 수 있습니다.

Console.WriteLine("Running Azure SQL indexer...");

try
{
      await indexerClient.RunIndexerAsync(indexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 429)
{
      Console.WriteLine("Failed to run indexer: {0}", ex.Message);
}

4 - 솔루션 빌드

F5 키를 눌러 솔루션을 빌드하고 실행합니다. 디버그 모드로 프로그램을 실행합니다. 콘솔 창에서는 각 작업의 상태를 보고합니다.

프로그램의 콘솔 출력을 보여 주는 스크린샷.

코드는 Visual Studio에서 로컬로 실행되어 Azure의 검색 서비스에 연결됩니다. 그러면 Azure SQL Database에 연결되어 데이터 세트를 검색합니다. 이러한 많은 작업을 수행하는 경우 몇 가지 잠재적인 실패 지점이 있습니다. 오류가 발생하면 먼저 다음 조건을 확인하세요.

  • 제공하는 검색 서비스 연결 정보는 전체 URL입니다. 서비스 이름만 입력하면 인덱스 생성 시 연결 오류와 함께 작업이 중지됩니다.

  • appsettings.json에 있는 데이터베이스 연결 정보입니다. 해당 항목은 포털에서 가져온 ADO.NET 연결 문자열이며 데이터베이스에 유효한 사용자 이름 및 암호를 포함하도록 수정되어야 합니다. 사용자 계정에는 데이터를 검색할 수 있는 권한이 있어야 합니다. 로컬 클라이언트 IP 주소는 방화벽을 통해 인바운드 액세스가 허용되어야 합니다.

  • 리소스 제한 무료 계층에는 인덱스, 인덱서, 데이터 원본 3개로 제한되어 있습니다. 최대 제한에 도달하면 서비스는 새 개체를 만들 수 없습니다.

Azure Portal을 사용하여 개체 만들기를 확인한 다음, Search 탐색기를 사용하여 인덱스를 쿼리합니다.

  1. Azure Portal에 로그인하고, 검색 서비스 왼쪽 탐색 창에서 각 페이지를 차례로 열어 개체가 만들어졌는지 확인합니다. 인덱스, 인덱서데이터 원본에는 각각 "hotels-sql-idx", "hotels-sql-indexer" 및 "hotels-sql-ds"가 있습니다.

  2. 인덱스 탭에서 hotels-sql-idx 인덱스를 선택합니다. hotels 페이지에서 첫 번째 탭은 Search 탐색기입니다.

  3. 검색을 선택하여 빈 쿼리를 실행합니다.

    인덱스에 있는 세 개의 항목이 JSON 문서로 반환됩니다. 전체 구조를 볼 수 있도록 검색 탐색기는 JSON으로 문서를 반환합니다.

    대상 인덱스에 대한 Search Explorer 쿼리 스크린샷.

  4. 그런 다음, 쿼리 매개 변수를 입력할 수 있도JSON 보기로 전환합니다.

    {
         "search": "river",
         "count": true
    }
    

    이 쿼리는 river 용어의 전체 텍스트 검색을 호출하고 결과에는 일치하는 문서 수가 포함됩니다. 일치하는 문서 수를 반환하는 작업은 수많은 문서를 포함하는 대규모 인덱스가 있을 때 시나리오를 테스트하는 경우 유용합니다. 이 경우에 하나의 문서만이 쿼리와 일치합니다.

  5. 마지막으로 검색 결과를 관심 필드로 제한하는 매개 변수를 입력합니다.

    {
         "search": "river",
         "select": "hotelId, hotelName, baseRate, description",
         "count": true
    }
    

    쿼리 응답이 선택한 필드로 줄어들어 더 간결한 출력이 표시됩니다.

다시 설정하고 다시 실행

초기 개발 실험 단계에서 설계 반복에 대한 가장 실용적인 방법은 Azure AI 검색에서 개체를 삭제하고 코드에서 이를 다시 작성하도록 허용하는 것입니다. 리소스 이름은 고유합니다. 개체를 삭제하면 동일한 이름을 사용하여 개체를 다시 만들 수 있습니다.

이 자습서의 샘플 코드는 기존 개체가 있는지 확인하고 코드를 다시 실행할 수 있도록 삭제합니다.

또한 포털을 사용하여 인덱스, 인덱서 및 데이터 원본을 삭제할 수도 있습니다.

리소스 정리

사용자 고유의 구독에서 작업하는 경우 프로젝트의 끝에서 더 이상 필요하지 않은 리소스를 제거하는 것이 좋습니다. 계속 실행되는 리소스에는 요금이 부과될 수 있습니다. 리소스를 개별적으로 삭제하거나 리소스 그룹을 삭제하여 전체 리소스 세트를 삭제할 수 있습니다.

왼쪽 탐색 창의 모든 리소스 또는 리소스 그룹 링크를 사용하여 포털에서 리소스를 찾고 관리할 수 있습니다.

다음 단계

SQL Database 인덱싱의 기본 사항을 익혔으면 인덱서 구성에 대해 자세히 살펴보겠습니다.