본문 바로가기
WIKI 기술 지식 베이스

JavaScript client

원문 보기 위키 갱신

출처: 문서

본문

JavaScript 클라이언트

OpenSearch JavaScript(JS) 클라이언트는 OpenSearch 클러스터와 상호작용할 수 있는 더 안전하고 쉬운 방법을 제공합니다. 브라우저에서 OpenSearch를 사용하여 데이터를 공개적으로 노출할 수 있는 위험을 감수하는 대신, 클러스터에 요청을 보내는 역할을 하는 OpenSearch 클라이언트를 구축할 수 있습니다. 클라이언트의 전체 API 문서와 추가 예제는 JS 클라이언트 API 문서를 참조하세요.

클라이언트에는 클러스터에서 다양한 작업을 수행하고 표준 응답 본문을 반환할 수 있는 API 라이브러리가 포함되어 있습니다. 여기에 있는 예제는 인덱스 생성, 문서 추가, 데이터 검색과 같은 몇 가지 기본 작업을 보여줍니다.

헬퍼 메서드를 사용하면 복잡한 API 작업을 간소화할 수 있습니다. 자세한 내용은 헬퍼 메서드를 참조하세요. 더 고급 인덱스 작업에 대해서는 GitHub의 opensearch-js 가이드를 참조하세요.

JavaScript 클라이언트 설치하기

클라이언트는 Node.js 14 이상이 필요합니다.

프로젝트에 클라이언트를 추가하려면 npm에서 설치하세요.

npm install @opensearch-project/opensearch

{% include copy.html %}

클라이언트의 특정 버전을 설치하려면 다음 명령을 실행하세요.

npm install @opensearch-project/opensearch@<version>

{% include copy.html %}

클라이언트를 수동으로 추가하거나 소스 코드만 살펴보려면 GitHub의 opensearch-js를 참조하세요.

그런 다음 클라이언트를 require 하세요.

const { Client } = require("@opensearch-project/opensearch");

{% include copy.html %}

OpenSearch에 연결하기

기본 OpenSearch 호스트에 연결하려면 Security 플러그인을 사용하는 경우 주소 https://localhost:9200으로 클라이언트 객체를 생성하세요.

var host = "localhost";
var protocol = "https";
var port = 9200;
var auth = "admin:<custom-admin-password>"; // For testing only. Don't store credentials in code.
var ca_certs_path = "/full/path/to/root-ca.pem";

// Optional client certificates if you don't want to use HTTP basic authentication.
// var client_cert_path = '/full/path/to/client.pem'
// var client_key_path = '/full/path/to/client-key.pem'

// Create a client with SSL/TLS enabled.
var { Client } = require("@opensearch-project/opensearch");
var fs = require("fs");
var client = new Client({
  node: protocol + "://" + auth + "@" + host + ":" + port,
  ssl: {
    ca: fs.readFileSync(ca_certs_path),
    // You can turn off certificate verification (rejectUnauthorized: false) if you're using 
    // self-signed certificates with a hostname mismatch.
    // cert: fs.readFileSync(client_cert_path),
    // key: fs.readFileSync(client_key_path)
  },
});

{% include copy.html %}

Security 플러그인을 사용하지 않는 경우 주소 http://localhost:9200으로 클라이언트 객체를 생성하세요.

var host = "localhost";
var protocol = "http";
var port = 9200;

// Create a client
var { Client } = require("@opensearch-project/opensearch");
var client = new Client({
  node: protocol + "://" + host + ":" + port
});

{% include copy.html %}

Amazon OpenSearch Service 인증: AWS Signature Version 4

AWS SDK for JavaScript V3를 사용하여 요청에 서명하려면 V3 자격 증명 공급자 패키지를 설치하세요.

npm install @aws-sdk/credential-provider-node

{% include copy.html %}

AWS SDK for JavaScript V2를 사용하여 요청에 서명하려면 V2 SDK를 설치하세요.

npm install aws-sdk

{% include copy.html %}

AWS SDK for JavaScript V2는 2025년 9월 8일에 지원이 종료되었습니다. 새 애플리케이션에는 이 섹션의 AWS SDK for JavaScript V3 예제를 사용하세요. {: .note}

다음 예제에서는 엔드포인트를 Amazon OpenSearch Service 콘솔의 도메인 또는 컬렉션 세부 정보 페이지에 나열된 도메인 또는 컬렉션 엔드포인트로 바꾸세요.

AWS V2 SDK로 인증하려면 다음 코드를 사용하세요.

const AWS = require('aws-sdk'); // V2 SDK.
const { Client } = require('@opensearch-project/opensearch');
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws');

const client = new Client({
  ...AwsSigv4Signer({
    region: 'us-east-1',
    service: 'es',
    // Must return a Promise that resolves to an AWS.Credentials object.
    // This function acquires the credentials when the client starts and
    // when the credentials expire.
    // The client refreshes the credentials only when they expire, using
    // Credentials.refreshPromise when it is available.

    // Example with AWS SDK V2:
    getCredentials: () =>
      new Promise((resolve, reject) => {
        // Any other method to acquire a new Credentials object can be used.
        AWS.config.getCredentials((err, credentials) => {
          if (err) {
            reject(err);
          } else {
            resolve(credentials);
          }
        });
      }),
  }),
  node: 'https://search-<domain-name>-<id>.us-east-1.es.amazonaws.com', // OpenSearch domain endpoint
});

{% include copy.html %}

Amazon OpenSearch Serverless용 AWS V2 SDK로 인증하려면 다음 코드를 사용하세요.

const AWS = require('aws-sdk'); // V2 SDK.
const { Client } = require('@opensearch-project/opensearch');
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws');

const client = new Client({
  ...AwsSigv4Signer({
    region: 'us-east-1',
    service: 'aoss',
    // Must return a Promise that resolves to an AWS.Credentials object.
    // This function acquires the credentials when the client starts and
    // when the credentials expire.
    // The client refreshes the credentials only when they expire, using
    // Credentials.refreshPromise when it is available.

    // Example with AWS SDK V2:
    getCredentials: () =>
      new Promise((resolve, reject) => {
        // Any other method to acquire a new Credentials object can be used.
        AWS.config.getCredentials((err, credentials) => {
          if (err) {
            reject(err);
          } else {
            resolve(credentials);
          }
        });
      }),
  }),
  node: 'https://<collection-id>.us-east-1.aoss.amazonaws.com', // OpenSearch Serverless collection endpoint
});

{% include copy.html %}

AWS V3 SDK로 인증하려면 다음 코드를 사용하세요.

const { defaultProvider } = require('@aws-sdk/credential-provider-node'); // V3 SDK.
const { Client } = require('@opensearch-project/opensearch');
// Use the aws-v3 import path with the AWS SDK for JavaScript V3. It lazy loads
// only the V3 credential providers.
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws-v3');

const client = new Client({
  ...AwsSigv4Signer({
    region: 'us-east-1',
    service: 'es',  // 'aoss' for OpenSearch Serverless
    // Must return a Promise that resolves to a credentials object containing
    // accessKeyId, secretAccessKey, and, optionally, sessionToken and expiration.
    // This function acquires the credentials when the client starts and
    // when the credentials expire.
    // The client treats the credentials as expired if they are within
    // requestTimeout milliseconds of expiration (the default is 30,000).

    // Example with AWS SDK V3:
    getCredentials: () => {
      // Any other credential provider that returns such a Promise can be used.
      const credentialsProvider = defaultProvider();
      return credentialsProvider();
    },
  }),
  node: 'https://search-<domain-name>-<id>.us-east-1.es.amazonaws.com', // OpenSearch domain endpoint
  // node: 'https://<collection-id>.us-east-1.aoss.amazonaws.com' for an OpenSearch Serverless collection endpoint
});

{% include copy.html %}

Amazon OpenSearch Serverless용 AWS V3 SDK로 인증하려면 다음 코드를 사용하세요.

const { defaultProvider } = require('@aws-sdk/credential-provider-node'); // V3 SDK.
const { Client } = require('@opensearch-project/opensearch');
// Use the aws-v3 import path with the AWS SDK for JavaScript V3. It lazy loads
// only the V3 credential providers.
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws-v3');

const client = new Client({
  ...AwsSigv4Signer({
    region: 'us-east-1',
    service: 'aoss',
    // Must return a Promise that resolves to a credentials object containing
    // accessKeyId, secretAccessKey, and, optionally, sessionToken and expiration.
    // This function acquires the credentials when the client starts and
    // when the credentials expire.
    // The client treats the credentials as expired if they are within
    // requestTimeout milliseconds of expiration (the default is 30,000).

    // Example with AWS SDK V3:
    getCredentials: () => {
      // Any other credential provider that returns such a Promise can be used.
      const credentialsProvider = defaultProvider();
      return credentialsProvider();
    },
  }),
  node: 'https://<collection-id>.us-east-1.aoss.amazonaws.com', // OpenSearch Serverless collection endpoint
});

{% include copy.html %}

Amazon OpenSearch Serverless는 OpenSearch API 작업의 하위 집합을 지원하며 이 페이지의 예제에서 사용된 refresh 매개변수를 지원하지 않습니다. 자세한 내용은 Amazon OpenSearch Serverless에서 지원되는 작업 및 플러그인을 참조하세요. {: .note}

AWS Lambda 함수 내에서 인증

AWS Lambda 함수 내에서 핸들러 함수 외부에 선언된 객체는 초기화 상태를 유지합니다. 자세한 내용은 Lambda 실행 환경을 참조하세요. 따라서 OpenSearch 클라이언트를 핸들러 함수 외부에서 초기화하여 후속 호출에서 원래 연결을 재사용할 수 있도록 해야 합니다. 이렇게 하면 효율성이 향상되고 매번 새 연결을 생성할 필요가 없습니다.

핸들러 함수 내에서 클라이언트를 초기화하면 ConnectionError: getaddrinfo EMFILE error가 발생할 위험이 있습니다. 이 오류는 후속 호출에서 여러 연결이 생성되어 시스템의 파일 디스크립터 제한을 초과할 때 발생합니다.

다음 AWS Lambda 함수 코드 예제는 OpenSearch 클라이언트의 올바른 초기화를 보여줍니다.

const { defaultProvider } = require('@aws-sdk/credential-provider-node'); // V3 SDK.
const { Client } = require('@opensearch-project/opensearch');
// Use the aws-v3 import path with the AWS SDK for JavaScript V3. It lazy loads
// only the V3 credential providers.
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws-v3');

const client = new Client({
  ...AwsSigv4Signer({
    region: 'us-east-1',
    service: 'es',  // 'aoss' for OpenSearch Serverless
    // Must return a Promise that resolves to a credentials object containing
    // accessKeyId, secretAccessKey, and, optionally, sessionToken and expiration.
    // This function acquires the credentials when the client starts and
    // when the credentials expire.
    // The client treats the credentials as expired if they are within
    // requestTimeout milliseconds of expiration (the default is 30,000).

    // Example with AWS SDK V3:
    getCredentials: () => {
      // Any other credential provider that returns such a Promise can be used.
      const credentialsProvider = defaultProvider();
      return credentialsProvider();
    },
  }),
  node: 'https://search-<domain-name>-<id>.us-east-1.es.amazonaws.com', // OpenSearch domain endpoint
  // node: 'https://<collection-id>.us-east-1.aoss.amazonaws.com' for an OpenSearch Serverless collection endpoint
});

exports.handler = async (event, context) => {
  // Use the already initialized client
  const response = await client.indices.create({
    index: "students",
  });

  return response.body;
};

{% include copy.html %}

인덱스 생성

다음 예제는 기본 샤드 1개와 복제본 1개로 인덱스를 생성합니다. gradDate 필드를 yyyy-MM-dd 형식의 date로 명시적으로 매핑합니다. OpenSearch는 문서를 인덱싱할 때 다른 문서 필드를 동적으로 매핑합니다.

var index_name = "students";

var response = await client.indices.create({
  index: index_name,
  body: {
    settings: {
      index: {
        number_of_shards: 1,
        number_of_replicas: 1,
      },
    },
    mappings: {
      properties: {
        gradDate: { type: "date", format: "yyyy-MM-dd" },
      },
    },
  },
});

{% include copy.html %}

문서 인덱싱

클라이언트의 index 메서드를 사용하여 OpenSearch에 문서를 인덱싱하세요.

var student = { firstName: "John", lastName: "Doe", gpa: 3.89, gradDate: "2022-05-15" };

var response = await client.index({
  index: index_name,
  id: "1",
  body: student,
  refresh: true,
});

{% include copy.html %}

벌크 인덱싱

클라이언트의 bulk 메서드를 사용하여 하나의 요청으로 여러 문서를 인덱싱하세요. 요청 본문은 각 작업 뒤에 해당 작업이 적용되는 문서가 오는 배열입니다.

var response = await client.bulk({
  body: [
    { index: { _index: index_name, _id: "2" } },
    { firstName: "Paulo", lastName: "Santos", gpa: 3.93, gradDate: "2021-05-20" },
    { index: { _index: index_name, _id: "3" } },
    { firstName: "Shirley", lastName: "Rodriguez", gpa: 3.91, gradDate: "2019-05-10" },
  ],
  refresh: true,
});

{% include copy.html %}

배열, 스트림 또는 비동기 생성기에서 요청 본문을 작성하려면 벌크 헬퍼를 사용하세요.

문서 검색

클라이언트의 search 메서드를 사용하여 인덱스의 모든 문서를 검색하세요.

var response = await client.search({
  index: index_name,
  body: {
    query: {
      match_all: {},
    },
  },
});
response.body.hits.hits.forEach((hit) => console.log(hit._source));

{% include copy.html %}

response.body.hits.hits의 각 항목은 일반 JavaScript 객체입니다. 문서 ID는 _id 속성에 있고, 문서 필드는 _source 객체의 속성입니다.

response.body.hits.hits.forEach((hit) => {
  console.log(
    `ID: ${hit._id}, name: ${hit._source.firstName} ${hit._source.lastName}, GPA: ${hit._source.gpa}, graduation date: ${hit._source.gradDate}`
  );
});

{% include copy.html %}

range 쿼리를 사용하여 검색하세요.

var response = await client.search({
  index: index_name,
  body: {
    query: {
      range: {
        gradDate: {
          gte: "2019-01-01",
          lte: "2019-12-31",
        },
      },
    },
  },
});

{% include copy.html %}

결과 페이지 매기기

결과를 페이지로 나누려면 from 및 size 매개변수를 사용하세요. 다음 예제는 학생을 졸업 날짜별로 정렬하고 결과를 한 번에 두 개씩 검색합니다. 첫 번째 요청은 첫 번째 페이지 결과를 반환하고, 두 번째 요청은 다음 페이지를 반환합니다.

var response = await client.search({
  index: index_name,
  body: {
    from: 0,
    size: 2,
    sort: [{ gradDate: "asc" }],
  },
});
response.body.hits.hits.forEach((hit) => console.log(hit._source));

var nextPage = await client.search({
  index: index_name,
  body: {
    from: 2,
    size: 2,
    sort: [{ gradDate: "asc" }],
  },
});
nextPage.body.hits.hits.forEach((hit) => console.log(hit._source));

{% include copy.html %}

from 및 size 매개변수는 처음 몇 페이지의 결과에 잘 작동합니다. 많은 수의 결과를 페이지로 나누려면 search_after와 함께 포인트 인 타임을 사용하세요. 자세한 내용은 결과 페이지 매기기를 참조하세요.

문서 업데이트

클라이언트의 update 메서드를 사용하여 문서를 업데이트하세요. doc 객체에는 업데이트할 필드만 포함됩니다.

var response = await client.update({
  index: index_name,
  id: "1",
  body: {
    doc: { gpa: 3.92 },
  },
});

{% include copy.html %}

문서 삭제

클라이언트의 delete 메서드를 사용하여 문서를 삭제하세요.

var response = await client.delete({
  index: index_name,
  id: "3",
  refresh: true,
});

{% include copy.html %}

인덱스 삭제

indices.delete() 메서드를 사용하여 인덱스를 삭제하세요.

var response = await client.indices.delete({
  index: index_name,
});

{% include copy.html %}

샘플 프로그램

이 샘플 프로그램은 앞선 섹션의 코드를 결합합니다. Security 플러그인이 활성화된 클러스터에 연결합니다. Security 플러그인 없이 클러스터에 연결하려면 // Without security 주석이 표시된 줄을 변경하세요.

이 샘플 프로그램은 테스트 전용입니다. 코드에 자격 증명을 지정합니다. 프로덕션에서는 안전한 위치에서 자격 증명을 로드하세요. {: .warning}

다음 샘플 프로그램은 클라이언트를 생성하고, 인덱스를 생성하고, 문서를 개별적으로 및 벌크로 인덱싱하고, 문서를 검색하고, 문서를 업데이트하고, 문서를 삭제한 다음 인덱스를 삭제합니다.

"use strict";

var host = "localhost";
var protocol = "https"; // Without security, use "http"
var port = 9200;
// Without security, remove the following line
var auth = "admin:<custom-admin-password>";
var ca_certs_path = "/full/path/to/root-ca.pem"; // Without security, remove this line

// Optional client certificates if you don't want to use HTTP basic authentication
// var client_cert_path = '/full/path/to/client.pem'
// var client_key_path = '/full/path/to/client-key.pem'

// Create a client with SSL/TLS enabled
var { Client } = require("@opensearch-project/opensearch");
var fs = require("fs"); // Without security, remove this line
var client = new Client({
  // Without security, use node: protocol + "://" + host + ":" + port,
  node: protocol + "://" + auth + "@" + host + ":" + port,
  ssl: { // Without security, remove the ssl block
    ca: fs.readFileSync(ca_certs_path),
    // You can turn off certificate verification (rejectUnauthorized: false) if you're using
    // self-signed certificates with a hostname mismatch.
    // cert: fs.readFileSync(client_cert_path),
    // key: fs.readFileSync(client_key_path)
  },
});

async function main() {
  // Create the index
  var index_name = "students";
  console.log("Creating index......");
  var response = await client.indices.create({
    index: index_name,
    body: {
      settings: {
        index: {
          number_of_shards: 1,
          number_of_replicas: 1,
        },
      },
      mappings: {
        properties: {
          gradDate: { type: "date", format: "yyyy-MM-dd" },
        },
      },
    },
  });
  console.log("Index created: " + response.body.index);

  // Index a document
  console.log("\nIndexing one student......");
  var student = { firstName: "John", lastName: "Doe", gpa: 3.89, gradDate: "2022-05-15" };
  response = await client.index({
    index: index_name,
    id: "1",
    body: student,
    refresh: true,
  });
  console.log("Result: " + response.body.result + ", id: " + response.body._id + ", version: " + response.body._version);

  // Bulk index documents
  console.log("\nIndexing many students......");
  response = await client.bulk({
    body: [
      { index: { _index: index_name, _id: "2" } },
      { firstName: "Paulo", lastName: "Santos", gpa: 3.93, gradDate: "2021-05-20" },
      { index: { _index: index_name, _id: "3" } },
      { firstName: "Shirley", lastName: "Rodriguez", gpa: 3.91, gradDate: "2019-05-10" },
    ],
    refresh: true,
  });
  console.log("Errors: " + response.body.errors);
  response.body.items.forEach((item) =>
    console.log("  " + item.index.result + " id: " + item.index._id));

  // Search for all students
  console.log("\nSearching for all students......");
  response = await client.search({
    index: index_name,
    body: {
      from: 0,
      size: 2,
      sort: [{ gradDate: "asc" }],
    },
  });
  console.log("Total hits: " + response.body.hits.total.value);
  console.log("Page 1:");
  response.body.hits.hits.forEach((hit) => console.log("  " + JSON.stringify(hit._source)));
  response = await client.search({
    index: index_name,
    body: {
      from: 2,
      size: 2,
      sort: [{ gradDate: "asc" }],
    },
  });
  console.log("Page 2:");
  response.body.hits.hits.forEach((hit) => console.log("  " + JSON.stringify(hit._source)));

  // Search for students who graduated in 2019
  console.log("\nSearching for students who graduated in 2019......");
  response = await client.search({
    index: index_name,
    body: {
      query: {
        range: {
          gradDate: {
            gte: "2019-01-01",
            lte: "2019-12-31",
          },
        },
      },
    },
  });
  console.log("Total hits: " + response.body.hits.total.value);
  response.body.hits.hits.forEach((hit) => console.log("  " + JSON.stringify(hit._source)));

  // Update a document
  console.log("\nUpdating a student's GPA......");
  response = await client.update({
    index: index_name,
    id: "1",
    body: {
      doc: { gpa: 3.92 },
    },
  });
  console.log("Result: " + response.body.result + ", version: " + response.body._version);

  // Get the updated document
  response = await client.get({
    index: index_name,
    id: "1",
  });
  console.log("Updated document: " + JSON.stringify(response.body._source));

  // Delete a document
  console.log("\nDeleting a student......");
  response = await client.delete({
    index: index_name,
    id: "3",
    refresh: true,
  });
  console.log("Result: " + response.body.result);

  // Delete the index
  console.log("\nDeleting the index......");
  response = await client.indices.delete({
    index: index_name,
  });
  console.log("Acknowledged: " + response.body.acknowledged);
}

main().catch(console.log);

{% include copy.html %}

프로그램은 다음 출력을 생성합니다.

Creating index......
Index created: students

Indexing one student......
Result: created, id: 1, version: 1

Indexing many students......
Errors: false
  created id: 2
  created id: 3

Searching for all students......
Total hits: 3
Page 1:
  {"firstName":"Shirley","lastName":"Rodriguez","gpa":3.91,"gradDate":"2019-05-10"}
  {"firstName":"Paulo","lastName":"Santos","gpa":3.93,"gradDate":"2021-05-20"}
Page 2:
  {"firstName":"John","lastName":"Doe","gpa":3.89,"gradDate":"2022-05-15"}

Searching for students who graduated in 2019......
Total hits: 1
  {"firstName":"Shirley","lastName":"Rodriguez","gpa":3.91,"gradDate":"2019-05-10"}

Updating a student's GPA......
Result: updated, version: 2
Updated document: {"firstName":"John","lastName":"Doe","gpa":3.92,"gradDate":"2022-05-15"}

Deleting a student......
Result: deleted

Deleting the index......
Acknowledged: true

서킷 브레이커

memoryCircuitBreaker 옵션은 응답 페이로드가 클라이언트에서 사용 가능한 힙 메모리에 비해 너무 커서 발생하는 오류를 방지하는 데 사용할 수 있습니다.

memoryCircuitBreaker 객체에는 두 개의 필드가 포함됩니다.

  • enabled: 서킷 브레이커를 켜거나 끄는 데 사용되는 부울입니다. 기본값은 false입니다.
  • maxPercentage: 서킷 브레이커가 작동하는지 여부를 결정하는 임계값입니다. 유효한 값은 백분율을 십진수 형태로 나타내는 [0, 1] 범위의 부동 소수점입니다. 이 범위를 초과하는 값은 1.0으로 수정됩니다.

다음 예제는 서킷 브레이커를 활성화하고 임계값을 사용 가능한 힙 크기 제한의 80%로 설정하여 클라이언트를 인스턴스화합니다.

var client = new Client({
  memoryCircuitBreaker: {
    enabled: true,
    maxPercentage: 0.8,
  },
});

{% include copy.html %}

관련 문서

더 알아보기 (Learn more)