다음을 통해 공유


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

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

사전 요구 사항

Azure Function 만들기

이 예제에서는 Azure 함수를 사용하여 웹 API를 호스트하는 개념을 설명하지만 다른 방법도 가능합니다. 인식 기술에 대한 인터페이스 요구 사항을 충족하기만 하면, 사용하는 방식은 중요하지 않습니다. 그러나 Azure Functions를 사용하면 사용자 지정 기술을 쉽게 만들 수 있습니다.

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

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

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

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

새 HTTP 트리거 함수도 함수 앱 프로젝트의 Concatenator 폴더에 생성됩니다. 그 안에 다음 내용이 포함된 "__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 키를 눌러 명령 팔레트를 엽니다. 명령 팔레트에서 함수 앱에 배포... 를 검색하고 선택합니다.

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

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

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

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

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

  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 함수의 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"
            }
          ]
      }
  ]
}

검색 인덱스의 "fullname" 필드에 "merged_title_author"를 보내려면 인덱서 정의에 "outputFieldMapping"을 추가해야 합니다.

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