다음을 통해 공유


예: Python을 사용하여 사용자 지정 기술 만들기(보관됨)

이 예제는 보관되고 지원되지 않습니다. Python 및 Visual Studio Code를 사용하여 웹 API 사용자 지정 기술을 만드는 방법을 설명했습니다. 이 예제에서는 사용자 지정 기술 인터페이스를 구현하는 Azure Function 사용했습니다.

필수 구성 요소

Azure 함수 만들기

이 예제에서는 Azure Function을 사용하여 웹 API를 호스팅하는 개념을 보여 주지만 다른 방법은 가능합니다. 인지 기술에 대한 인터페이스 요구 사항을 충족하는 한, 수행하는 접근 방식은 비물질적입니다. 그러나 Azure Functions를 사용하면 사용자 지정 기술을 쉽게 만들 수 있습니다.

함수에 대한 프로젝트 만들기

Visual Studio Code의 Azure Functions 프로젝트 템플릿은 Azure의 함수 앱에 게시할 수 있는 로컬 프로젝트를 만듭니다. 함수 앱을 사용하면 리소스 관리, 배포 및 공유를 위한 논리 단위로 함수를 그룹화할 수 있습니다.

  1. Visual Studio Code에서 F1 키를 눌러 명령 팔레트를 엽니다. 명령 팔레트에서 Azure Functions: Create new project...검색하고 선택합니다.
  2. 프로젝트 작업 영역에 대한 디렉터리 위치를 선택하고 선택합니다. 이미 다른 작업 영역의 일부인 프로젝트 폴더를 사용하지 마세요.
  3. 함수 앱 프로젝트에 대한 언어를 선택합니다. 이 자습서에서는 Python을 선택합니다.
  4. Python 버전을 선택합니다(버전 3.7.5는 Azure Functions에서 지원됨).
  5. 프로젝트의 첫 번째 함수에 대한 템플릿을 선택합니다. HTTP 트리거 선택하여 새 함수 앱에서 HTTP 트리거 함수를 만듭니다.
  6. 함수 이름을 제공합니다. 이 경우 연결기
  7. 권한 부여 수준으로 함수 선택합니다. 함수 액세스 키를 사용하여 함수의 HTTP 엔드포인트를 호출합니다.
  8. 프로젝트를 여는 방법을 지정합니다. 이 단계에서는 작업 영역에 추가 선택하여 현재 작업 영역에서 함수 앱을 만듭니다.

Visual Studio Code는 새 작업 영역에 함수 앱 프로젝트를 만듭니다. 이 프로젝트에는 host.json 및 local.settings.jsonconfiguration 파일과 언어별 프로젝트 파일이 포함됩니다.

함수 앱 프로젝트의 Concatenator 폴더에도 새 HTTP 트리거 함수가 만들어집니다. 그 안에는 "__init__.py"라는 파일이 있으며, 이 콘텐츠는 다음과 같습니다.

import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello {name}!")
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             status_code=400
        )

이제 사용자 지정 기술 인터페이스를 따르도록 해당 코드를 수정해 보겠습니다. 기본 코드를 다음 콘텐츠로 바꿉다.

import logging
import azure.functions as func
import json

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    try:
        body = json.dumps(req.get_json())
    except ValueError:
        return func.HttpResponse(
             "Invalid body",
             status_code=400
        )
    
    if body:
        result = compose_response(body)
        return func.HttpResponse(result, mimetype="application/json")
    else:
        return func.HttpResponse(
             "Invalid body",
             status_code=400
        )


def compose_response(json_data):
    values = json.loads(json_data)['values']
    
    # Prepare the Output before the loop
    results = {}
    results["values"] = []
    
    for value in values:
        output_record = transform_value(value)
        if output_record != None:
            results["values"].append(output_record)
    return json.dumps(results, ensure_ascii=False)

## Perform an operation on a record
def transform_value(value):
    try:
        recordId = value['recordId']
    except AssertionError  as error:
        return None

    # Validate the inputs
    try:         
        assert ('data' in value), "'data' field is required."
        data = value['data']        
        assert ('text1' in data), "'text1' field is required in 'data' object."
        assert ('text2' in data), "'text2' field is required in 'data' object."
    except AssertionError  as error:
        return (
            {
            "recordId": recordId,
            "errors": [ { "message": "Error:" + error.args[0] }   ]       
            })

    try:                
        concatenated_string = value['data']['text1'] + " " + value['data']['text2']  
        # Here you could do something more interesting with the inputs

    except:
        return (
            {
            "recordId": recordId,
            "errors": [ { "message": "Could not complete operation for record." }   ]       
            })

    return ({
            "recordId": recordId,
            "data": {
                "text": concatenated_string
                    }
            })

transform_value 메서드는 단일 레코드에 대한 작업을 수행합니다. 특정 요구 사항에 맞게 메서드를 수정할 수 있습니다. 필요한 입력 유효성 검사를 수행하고 작업을 완료할 수 없는 경우 오류 및 경고를 반환해야 합니다.

로컬로 코드 디버그

Visual Studio Code를 사용하면 코드를 쉽게 디버그할 수 있습니다. 'F5'를 누르거나 디버그 메뉴로 이동하여 디버깅 시작 선택합니다.

관심 있는 줄에서 'F9'를 눌러 코드에 중단점을 설정할 수 있습니다.

디버깅을 시작하면 함수가 로컬로 실행됩니다. Postman 또는 Fiddler와 같은 도구를 사용하여 localhost에 요청을 실행할 수 있습니다. 터미널 창에서 로컬 엔드포인트의 위치를 확인합니다.

Azure에서 함수 앱 만들기

함수 동작에 만족하면 게시할 수 있습니다. 지금까지 로컬로 작업했습니다. 이 섹션에서는 Azure에서 함수 앱을 만든 다음, 만든 앱에 로컬 프로젝트를 배포합니다.

Visual Studio Code에서 앱 만들기

  1. Visual Studio Code에서 F1 키를 눌러 명령 팔레트를 엽니다. 명령 팔레트에서 Azure에서 함수 앱 만들기를 검색하여 선택합니다.

  2. 여러 활성 구독이 있는 경우 이 앱에 대한 구독을 선택합니다.

  3. 함수 앱의 전역적으로 고유한 이름을 입력합니다. URL에 유효한 이름을 입력합니다.

  4. 런타임 스택을 선택하고 로컬에서 실행한 언어 버전을 선택합니다.

  5. 앱의 위치를 선택합니다. 가능하면 검색 서비스를 호스트하는 동일한 지역을 선택합니다.

앱을 만드는 데 몇 분 정도 걸립니다. 준비가 되면 새 앱이 현재 구독의 리소스함수 앱 아래에 표시됩니다.

Azure에 배포

  1. Visual Studio Code에서 F1 키를 눌러 명령 팔레트를 엽니다. 명령 팔레트에서 Deploy to Function App...을 검색하고 선택합니다.

  2. 만든 함수 앱을 선택합니다.

  3. 계속할지 확인한 다음 배포선택합니다. 출력 창에서 배포 상태를 모니터링할 수 있습니다.

  4. Azure 포털로 전환하고 모든 리소스로 이동합니다. 이전 단계에서 제공한 전역적으로 고유한 이름을 사용하여 배포한 함수 앱을 검색합니다.

    Visual Studio Code에서 함수 앱을 마우스 오른쪽 단추로 클릭하고 포털 열기를 선택할 수도 있습니다.

  5. 포털의 왼쪽에서 Functions선택한 다음, 만든 함수를 선택합니다.

  6. 함수의 개요 페이지에서 맨 위의 명령 모음에서 함수 URL 가져오기를 선택합니다. 이렇게 하면 URL을 복사하여 함수를 호출할 수 있습니다.

    Azure Portal의 함수 URL 가져오기 명령 스크린샷

Azure에서 함수 테스트

복사한 기본 호스트 키 및 URL을 사용하여 Azure Portal 내에서 함수를 테스트합니다.

  1. 왼쪽에 있는 개발자 섹션 아래에서 코드 + 테스트을 선택합니다.

  2. 명령 모음에서 테스트/실행 선택합니다.

  3. 입력의 경우 기본 키인 Post사용한 다음 요청 본문에 붙여넣습니다.

    {
        "values": [
            {
                "recordId": "e1",
                "data":
                {
                    "text1":  "Hello",
                    "text2":  "World"
                }
            },
            {
                "recordId": "e2",
                "data": "This is an invalid input"
            }
        ]
    }
    
  4. 실행을 선택합니다.

    입력 사양의 스크린샷

이 예제에서는 로컬 환경에서 함수를 실행할 때 이전에 본 것과 동일한 결과를 생성해야 합니다.

기술 세트에 추가

이제 새 사용자 지정 기술을 갖추게 되었으므로 기술 세트에 추가할 수 있습니다. 아래 예제에서는 기술을 호출하여 제목과 문서의 작성자를 단일 필드로 연결하여 merged_title_author 호출하는 방법을 보여 줍니다.

[your-function-url-here]을(를) 새 Azure Function의 URL로 변경합니다.

{
    "skills": [
      "[... other existing skills in the skillset are here]",  
      {
        "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
        "description": "Our new search custom skill",
        "uri": "https://[your-function-url-here]",        
          "context": "/document/merged_content/organizations/*",
          "inputs": [
            {
              "name": "text1",
              "source": "/document/metadata_title"
            },
            {
              "name": "text2",
              "source": "/document/metadata_author"
            },
          ],
          "outputs": [
            {
              "name": "text",
              "targetName": "merged_title_author"
            }
          ]
      }
  ]
}

인덱서 정의에서 "outputFieldMapping"을 추가하여, "merged_title_author"을 검색 인덱스의 "fullname" 필드로 보내는 것을 기억하십시오.

"outputFieldMappings": [
    {
        "sourceFieldName": "/document/content/merged_title_author",
        "targetFieldName": "fullname"
    }
]