<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Fernando Briano - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Fernando Briano - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/kr/search-labs/author/fernando-briano</link>
    </image>
    <link>https://www.elastic.co/kr/search-labs/author/fernando-briano</link>
    <atom:link href="https://www.elastic.co/kr/search-labs/rss/author/fernando-briano.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[kr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 10:20:44 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Elasticsearch Ruby 클라이언트를 위한 ES|QL 쿼리 빌더 소개]]></title>
    <description><![CDATA[최근 출시된 Elasticsearch Ruby 클라이언트용 ES|QL 쿼리 빌더를 사용하는 방법을 알아보세요. 루비 코드로 ES|QL 쿼리를 더 쉽게 작성할 수 있는 도구입니다.]]></description>
    <content:encoded><![CDATA[<p>최근에 Apache 2 라이선스에 따라 게시된 루비 보석( <a href="https://github.com/elastic/esql-ruby/"><code>elastic-esql</code></a>)을 출시했습니다. 이 보석을 사용하면 관용적 Ruby로 Elastic의 <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql">ES|QL</a> 쿼리를 빌드한 다음 ES|QL 쿼리 API와 함께 사용할 수 있습니다. ES|QL을 사용하면 개발자가 쿼리를 통해 Elasticsearch에 저장된 데이터를 필터링, 변환, 분석할 수 있습니다. "파이프" ( <code>|</code> )를 사용하여 단계별로 데이터를 작업합니다. 이 보석은 대신 Ruby 함수를 사용하며, 이를 원래 객체에 연결하여 더 복잡한 쿼리를 만들 수 있습니다:</p><p><strong>ESQL:</strong></p><p><strong>Ruby:</strong></p>Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending<h2>설치</h2><p>이 젬은 루비젬스에서 다음을 사용하여 설치할 수 있습니다:</p>gem install elastic-esql<p>또는 프로젝트의 젬파일에 추가할 수도 있습니다:</p>gem 'elastic-esql'<h2>사용법</h2><p>전체 쿼리를 한 번에 빌드하거나 <code>from</code> 또는 <code>row</code> 같은 소스 명령으로 쿼리 개체를 만든 다음 ES|QL 메서드를 체인으로 연결하여 빌드할 수 있습니다.</p>query = Elastic::ESQL.from('sample_data')
query.limit(2).sort('@timestamp')<p>겜은 <code>to_s</code> 메서드에서 코드를 ES|QL로 변환하므로 ES|QL 쿼리가 출력되거나 문자열로 캐스팅될 때 반환합니다:</p>query = Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending
query.to_s
# =&gt; "FROM sample_data | LIMIT 2 | SORT @timestamp DESC"<p>각 함수의 <code>!</code> 등가물을 사용하여 쿼리 객체를 인스턴스화하고 초기 상태를 변경할 수 있습니다:</p>query = Elastic::ESQL.from('sample_data')
query.to_s
# =&gt; "FROM sample_data"
query.limit!(2).sort!('@timestamp')
query.to_s
# =&gt; "FROM sample_data | LIMIT 2 | SORT @timestamp"<p>이 도구는 <code>enrich</code> 및 <code>sort</code> 과 같은 추가 단계를 ES|QL 함수에 연결하는 편리한 방법을 제공합니다. <code>Elastic::ESQL</code> 객체에서 <code>enrich</code> 을 호출하면 <code>on</code> 과 <code>with</code> 을 연결할 수 있습니다:</p>esql.enrich!('policy').on('a').with({ name: 'language_name' })<p><code>sort</code> 을 사용한 후 <code>desc</code>, <code>asc</code>, <code>nulls_first</code>, <code>nulls_last</code> 을 쿼리에 연결할 수도 있습니다:</p>Elastic::ESQL.from('sample_data').sort('@timestamp').asc.to_s
# =&gt; 'FROM sample_data | SORT @timestamp ASC'

Elastic::ESQL.from('sample_data').sort('@timestamp').desc.nulls_first.to_s
# =&gt; 'FROM sample_data | SORT @timestamp DESC NULLS FIRST'<p>또한 ES|QL 쿼리를 직접 작성하거나 아직 라이브러리에 추가되지 않은 기능을 사용하려는 경우 사용자 정의 문자열을 지원합니다. <code>custom</code> 은 쿼리 끝에 있는 문자열을 결합합니다. 파이프 문자를 추가하지 않고 함수에 전송되는 대로 추가합니다. 나머지 쿼리에는 공백 문자로 결합됩니다.</p>esql = Elastic::ESQL.from('sample_data')
esql.custom('| MY_VALUE = "test value"').to_s
# =&gt; 'FROM sample_data | MY_VALUE = "test value"'<p><code>custom</code> 함수를 연결할 수도 있습니다:</p>esql.custom('| MY_VALUE = "test value"').custom('| ANOTHER, VALUE')
'FROM sample_data | MY_VALUE = "test value" | ANOTHER, VALUE'<h2>루비 클라이언트와 함께 ES|QL 쿼리 빌더 사용하기</h2><p>쿼리 빌더는 쿼리 객체를 전송하여 <a href="https://github.com/elastic/elasticsearch-ruby">elasticsearch-ruby</a> 및 <code>esql.query</code> API와 함께 직접 사용할 수 있습니다:</p>require 'elasticsearch'
require 'elastic/esql'

client = Elasticsearch::Client.new
index = 'sample_data'

query = Elastic::ESQL.from(index)
                     .sort('@timestamp')
                     .desc
                     .where('event_duration &gt; 5000000')
                     .limit(3)
                     .eval({ duration_ms: 'ROUND(event_duration/1000000.0, 1)' })
client.esql.query(body: { query: query })<p>Elasticsearch Ruby 클라이언트의 ES|QL 도우미와 함께 사용할 수도 있으며, <a href="https://www.elastic.co/search-labs/blog/esql-ruby-helper-elasticsearch">자세히 알아보세요</a>:</p>require 'elasticsearch/helpers/esql_helper'

Elasticsearch::Helpers::ESQLHelper.query(client, query)<h2>독립형 도구로서</h2><p>이 보석은 관용적인 방식으로 ES|QL 쿼리를 작성하는 독립형 도구로 설계되었습니다. 런타임 종속성이 없으므로 공식 Elasticsearch Ruby 클라이언트와 함께 사용하거나 단독으로 사용할 수 있습니다.</p><p>생성된 쿼리는 애플리케이션이 Elasticsearch API와 상호 작용하는 모든 방식(Ruby 여부에 관계없이)으로 <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-query"><code>esql.query</code></a> API와 함께 사용할 수 있습니다. <code>elastic-esql</code> 으로 쿼리를 작성하면 생성된 문자열을 요청 본문에 <code>query</code> 매개변수로 API에 전송할 수 있습니다. </p><p>이전에 <a href="https://www.elastic.co/search-labs/blog/elasticsearch-ruby-tools">인기 있는 Ruby 도구와 함께 Elasticsearch를 사용하는</a> 방법에 대한 글을 쓴 적이 있습니다. 이 보석은 널리 사용되는 모든 Ruby 도구와 함께 ES|QL로 Elasticsearch를 쿼리하는 데 사용할 수 있습니다.</p><h2>결론</h2><p>이 라이브러리는 현재 개발 중이며 최종 API는 아직 완성되지 않았습니다. 현재 기술 프리뷰 버전으로 출시되었습니다. 현재 API 또는 일반적인 사용법에 대한 피드백이 있으시면 주저하지 마시고 <a href="https://github.com/elastic/esql-ruby/issues">새 이슈를 개설해</a> 주세요. 루비 ES|QL 쿼리 빌더에 대해 자세히 알아보려면 <a href="https://github.com/elastic/esql-ruby/?tab=readme-ov-file#ruby-esql-query-builder">README를</a> 참조하세요.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-query-builder-elasticsearch-ruby-client</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-query-builder-elasticsearch-ruby-client</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Fernando Briano]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt85d112ccca541b9e/6a17dccb4b055d6bfd4320cc/f8e1263ab53d356824a4fc539084151be80899db-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[OpenSearch에서 Elasticsearch로 Ruby 앱을 마이그레이션하는 방법]]></title>
    <description><![CDATA[OpenSearch 클라이언트에서 Elasticsearch 클라이언트로 Ruby 코드베이스를 마이그레이션하는 가이드입니다.]]></description>
    <content:encoded><![CDATA[<p>OpenSearch Ruby 클라이언트는 버전 <code>7.x</code> 에서 Elasticsearch Ruby 클라이언트에서 포크되었으므로 코드베이스가 비교적 유사합니다. 즉, OpenSearch에서 Elasticsearch로 Ruby 코드베이스를 마이그레이션할 때 각 클라이언트 라이브러리의 코드가 매우 친숙하게 보입니다. 이 블로그 포스팅에서는 OpenSearch를 사용하는 예제 Ruby 앱과 이 코드를 Elasticsearch로 마이그레이션하는 단계를 보여드리겠습니다.</p><p>두 클라이언트 모두 널리 사용되는 Apache 라이선스 2.0에 따라 출시되었으므로 오픈 소스 및 무료 소프트웨어입니다. Elasticsearch의 라이선스는 최근에 업데이트되었으며, 버전 8.16부터 Elasticsearch와 Kibana의 핵심은 OSI가 승인한 오픈 소스 라이선스 AGPL에 따라 게시되고 있습니다.</p><h2>Ruby 앱 마이그레이션 시 Elasticsearch 버전 고려하기</h2><p>마이그레이션할 때 고려해야 할 한 가지 사항은 어떤 버전의 Elasticsearch를 사용할 것인지입니다. 이 글을 작성하는 시점에 최신 안정 릴리스( <code>8.17.0</code>)를 사용하는 것이 좋습니다. Elasticsearch Ruby 클라이언트 부 버전은 Elasticsearch 부 버전을 따릅니다. 따라서 Elasticsearch <code>8.17.x</code> 의 경우 Ruby gem 버전 <code>8.17.x</code> 을 사용할 수 있습니다.</p><p>OpenSearch는 Elasticsearch 7.10.2에서 포크되었습니다. 따라서 API가 변경되어 다른 기능을 사용할 수 있습니다. 하지만 이는 이 글의 범위를 벗어나므로 예제 앱에서 가장 일반적인 작업만 살펴보겠습니다.</p><p>Ruby on Rails의 경우, 공식 Elasticsearch 클라이언트 또는 <a href="https://github.com/elastic/elasticsearch-rails/">Rails 통합 라이브러리를 사용할</a> 수 있습니다. 각각 안정적인 최신 버전의 Elasticsearch와 클라이언트로 마이그레이션하는 것이 좋습니다. <code>elasticsearch-rails</code> gem 버전 <code>8.0.0</code> 은 Rails <code>6.1</code>, <code>7.0</code> 및 <code>7.1</code> 와 Elasticsearch <code>8.x</code> 를 지원합니다.</p><h2>코드</h2><p>이 예제에서는 <a href="https://opensearch.org/docs/latest/install-and-configure/install-opensearch/tar/">타르볼에서 OpenSearch를 설치하는</a> 단계를 따랐습니다. 타르볼을 다운로드하고 압축을 푼 후, 나중에 클라이언트를 인스턴스화할 때 사용할 초기 관리자 비밀번호를 설정해야 했습니다.</p><p>다음과 같은 <code>Gemfile</code> 디렉터리를 만들었습니다:</p>source 'https://rubygems.org'

gem 'opensearch-ruby'<p><code>bundle install</code> 을 실행하면 내 프로젝트에 젬이 설치됩니다. 이 설치한 opensearch-ruby 버전은 <code>3.4.0</code> 이고 제가 실행 중인 OpenSearch 버전은 <code>2.18.0</code> 입니다. 같은 디렉토리에 있는 <code>example_code.rb</code> 파일에 코드를 작성했습니다. 이 파일의 초기 코드는 OpenSearch 클라이언트의 인스턴스화입니다:</p>require 'opensearch'

client = OpenSearch::Client.new(
  host: 'https://localhost:9200',
  user: 'admin',
  password: ENV['OPENSEARCH_INITIAL_ADMIN_PASSWORD'],
  transport_options: { ssl: { verify: false } }
)<p>테스트를 쉽게 하기 위해 사용자 가이드에 따라 전송 옵션 <code>ssl: { verify: false}</code> 매개변수를 전달하고 있습니다. 프로덕션 환경에서는 OpenSearch 배포에 따라 설정해야 합니다.</p><p>OpenSearch 버전 2.12.0부터 설치 스크립트를 실행할 때 <code>OPENSEARCH_INITIAL_ADMIN_PASSWORD</code> 환경 변수를 강력한 비밀번호로 설정해야 합니다. 타르볼에서 OpenSearch를 설치하는 단계에 따라 콘솔에서 변수를 내보냈고 이제 Ruby 스크립트에서 사용할 수 있습니다.</p><p>클라이언트가 OpenSearch에 연결하고 있는지 확인하기 위한 간단한 API는 <code>cluster.health</code> API를 사용합니다:</p>puts 'HEALTH:'
pp client.cluster.health<p>그리고 실제로 효과가 있습니다:</p>$ be ruby example_code.rb
HEALTH:
{"cluster_name"=&gt;"opensearch",
"status"=&gt;"yellow",
 "timed_out"=&gt;false,
 "number_of_nodes"=&gt;1,
 "number_of_data_nodes"=&gt;1,<p>Elasticsearch Ruby 클라이언트 문서에 있는 몇 가지 일반적인 예제를 테스트해 본 결과 예상대로 작동했습니다:</p>index = 'books'
puts 'Creating index'
response = client.indices.create(index: index)
puts response
# Creating index
# {"acknowledged"=&gt;true, "shards_acknowledged"=&gt;true, "index"=&gt;"books"}

puts 'Indexing a document'
document = { title: 'The Time Machine', author: 'H. G. Wells', year: 1895 }
response = client.index(index: index, body: document, refresh: true)
puts response
# Indexing document
# {"_index"=&gt;"books", "_id"=&gt;"esalT5MB4vnuJz5TtqOc", "_version"=&gt;1, "result"=&gt;"created", "forced_refresh"=&gt;true, "_shards"=&gt;{"total"=&gt;2, "successful"=&gt;1, "failed"=&gt;0}, "_seq_no"=&gt;0, "_primary_term"=&gt;1}

id = response['_id']
puts 'Getting document'
response = client.get(index: index, id: id)
puts response
# Getting document
# {"_index"=&gt;"books", "_id"=&gt;"esalT5MB4vnuJz5TtqOc", "_version"=&gt;1, "_seq_no"=&gt;0, "_primary_term"=&gt;1, "found"=&gt;true, "_source"=&gt;{"title"= &gt;"The Time Machine", "author"=&gt;"H. G. Wells", "year"=&gt;1895}}

puts "Does an index exist?"
puts client.indices.exists(index: 'imaginary_index')
# Does an index exist?
# false

puts 'Processing Bulk request'
body = [
  { index: { _index: 'books', data: { name: 'Leviathan Wakes', author: 'James S.A. Corey', release_date: '2011-06-02', page_count: 561 } } },
  { index: { _index: 'books', data: { name: 'Hyperion', author: 'Dan Simmons', release_date: '1989-05-26', page_count: 482 } } },
  { index: { _index: 'books', data: { name: 'Dune', author: 'Frank Herbert', release_date: '1965-06-01', page_count: 604 } } },
  { index: { _index: 'books', data: { name: 'Dune Messiah', author: 'Frank Herbert', release_date: '1969-10-15', page_count: 331 } } },
  { index: { _index: 'books', data: { name: 'Children of Dune', author: 'Frank Herbert', release_date: '1976-04-21', page_count: 408 } } },
  { index: { _index: 'books', data: { name: 'God Emperor of Dune', author: 'Frank Herbert', release_date: '1981-05-28', page_count: 454 } } },
  { index: { _index: 'books', data: { name: 'Consider Phlebas', author: 'Iain M. Banks', release_date: '1987-04-23', page_count: 471 } } },
  { index: { _index: 'books', data: { name: 'Pandora\'s Star', author: 'Peter F. Hamilton', release_date: '2004-03-02', page_count: 768 } } },
  { index: { _index: 'books', data: { name: 'Revelation Space', author: 'Alastair Reynolds', release_date: '2000-03-15', page_count: 585 } } },
  { index: { _index: 'books', data: { name: 'A Fire Upon the Deep', author: 'Vernor Vinge', release_date: '1992-06-01', page_count: 613 } } },
  { index: { _index: 'books', data: { name: 'Ender\'s Game', author: 'Orson Scott Card', release_date: '1985-06-01', page_count: 324 } } },
  { index: { _index: 'books', data: { name: '1984', author: 'George Orwell', release_date: '1985-06-01', page_count: 328 } } },
  { index: { _index: 'books', data: { name: 'Fahrenheit 451', author: 'Ray Bradbury', release_date: '1953-10-15', page_count: 227 } } },
  { index: { _index: 'books', data: { name: 'Brave New World', author: 'Aldous Huxley', release_date: '1932-06-01', page_count: 268 } } },
  { index: { _index: 'books', data: { name: 'Foundation', author: 'Isaac Asimov', release_date: '1951-06-01', page_count: 224 } } },
  { index: { _index: 'books', data: { name: 'The Giver', author: 'Lois Lowry', release_date: '1993-04-26', page_count: 208 } } },
  { index: { _index: 'books', data: { name: 'Slaughterhouse-Five', author: 'Kurt Vonnegut', release_date: '1969-06-01', page_count: 275 } } },
  { index: { _index: 'books', data: { name: 'The Hitchhiker\'s Guide to the Galaxy', author: 'Douglas Adams', release_date: '1979-10-12', page_count: 180 } } },
  { index: { _index: 'books', data: { name: 'Snow Crash', author: 'Neal Stephenson', release_date: '1992-06-01', page_count: 470 } } },
  { index: { _index: 'books', data: { name: 'Neuromancer', author: 'William Gibson', release_date: '1984-07-01', page_count: 271 } } },
  { index: { _index: 'books', data: { name: 'The Handmaid\'s Tale', author: 'Margaret Atwood', release_date: '1985-06-01', page_count: 311 } } },
  { index: { _index: 'books', data: { name: 'Starship Troopers', author: 'Robert A. Heinlein', release_date: '1959-12-01', page_count: 335 } } },
  { index: { _index: 'books', data: { name: 'The Left Hand of Darkness', author: 'Ursula K. Le Guin', release_date: '1969-06-01', page_count: 304 } } },
  { index: { _index: 'books', data: { name: 'The Moon is a Harsh Mistress', author: 'Robert A. Heinlein', release_date: '1966-04-01', page_count: 288 } } }
]
puts client.bulk(body: body, refresh: true)
# Processing Bulk request
# {"took"=&gt;38, "errors"=&gt;false, "items"=&gt;[{"index"=&gt;{"_index"=&gt;"books", "_id"=&gt;" ...

query = { query: { multi_match: { query: 'dune', fields: ['name'] } } }
puts 'Search results'
response = client.search(index: index, body: query)
puts response
# Search results
# {"_index"=&gt;"books", "_id"=&gt;"oEawT5MBOXHuGXdEu5Wu", "_score"=&gt;2.2886353, "_source"=&gt;{"name"=&gt;"Dune", "author"=&gt;"Frank Herbert", "release_date"=&gt;"1965-06-01", "page_count"=&gt;604}}
# {"_index"=&gt;"books", "_id"=&gt;"oUawT5MBOXHuGXdEu5Wu", "_score"=&gt;1.8893257, "_source"=&gt;{"name"=&gt;"Dune Messiah", "author"=&gt;"Frank Herbert", "release_date"=&gt;"1969-10-15", "page_count"=&gt;331}}
# {"_index"=&gt;"books", "_id"=&gt;"okawT5MBOXHuGXdEu5Wu", "_score"=&gt;1.6086557, "_source"=&gt;{"name"=&gt;"Children of Dune", "author"=&gt;"Frank Herbert", "release_date"=&gt;"1976-04-21", "page_count"=&gt;408}}
# {"_index"=&gt;"books", "_id"=&gt;"o0awT5MBOXHuGXdEu5Wu", "_score"=&gt;1.40059, "_source"=&gt;{"name"=&gt;"God Emperor of Dune", "author"=&gt;"Frank Herbert", "release_date"=&gt;"1981-05-28", "page_count"=&gt;454}}

puts 'Updating document'
document = { title: 'Walkaway', author: 'Cory Doctorow', release_date: '2017' }
response = client.index(index: index, body: document, refresh: true)
id = response['_id']
response = client.update(index: index, id: id, body: { doc: { release_date: '2017-04-26' } })
puts response
# Updating document
# {"_index"=&gt;"books", "_id"=&gt;"degnZJMBIGr4X0Yim55L", "_version"=&gt;2, "result"=&gt;"updated", "_shards"=&gt;{"total"=&gt;2, "successful"=&gt;1, "failed"=&gt;0}, "_seq_no"=&gt;26, "_primary_term"=&gt;1}

puts 'Retrieveing multiple documents'
response = client.search(index: index, body: { query: { match_all: {} }, size: 3, stored_fields: '_id' })
ids = response['hits']['hits']
ids.map { |a| a.delete('_score') }
response = client.mget(body: { docs: [{ _index: index, _id: ids }] })
puts response
# Retrieveing multiple documents
# {"docs"=&gt;[{"_index"=&gt;"books", "_id"=&gt;"qeg2ZJMBIGr4X0YiiqD2", "_version"=&gt;1, "_seq_no"=&gt;0, "_primary_term"=&gt;1, "found"=&gt;true, "_source"=&gt;{"title"=&gt;"The Time Machine", "author"=&gt;"H. G. Wells", "year"=&gt;1895}}, {"_index"=&gt;"books", "_id"=&gt;"q-g2ZJMBIGr4X0Yii6Ah", "_version"=&gt;1, "_seq_no"=&gt;1, "_primary_term"=&gt;1, "found"=&gt;true, "_source"=&gt;{"name"=&gt;"Leviathan Wakes", "author"=&gt;"James S.A. Corey", "release_date"=&gt;"2011-06-02", "page_count"=&gt;561}}, {"_index"=&gt;"books", "_id"=&gt;"rOg2ZJMBIGr4X0Yii6Ah", "_version"=&gt;1, "_seq_no"=&gt;2, "_primary_term"=&gt;1, "found"=&gt;true, "_source"=&gt;{"name"=&gt;"Hyperion", "author"=&gt;"Dan Simmons", "release_date"=&gt;"1989-05-26", "page_count"=&gt;482}}]}

puts "Count #{client.count(index: index)['count']}"
puts 'Deleting by query'
response = client.delete_by_query(index: index, body: { query: { match: { author: 'Robert A. Heinlein' } } }, refresh: true)
puts response
puts "Count #{client.count(index: index)['count']}"
# Count 26
# Deleting by query
# {"took"=&gt;16, "timed_out"=&gt;false, "total"=&gt;2, "deleted"=&gt;2, "batches"=&gt;1, "version_conflicts"=&gt;0, "noops"=&gt;0, "retries"=&gt;{"bulk"=&gt;0, "search"=&gt;0}, "throttled_millis"=&gt;0, "requests_per_second"=&gt;-1.0, "throttled_until_millis"=&gt;0, "failures"=&gt;[]}
# Count 24

puts 'Deleting document'
response = client.delete(index: index, id: id)
puts response
# Deleting document
# {"_index"=&gt;"books", "_id"=&gt;"nEawT5MBOXHuGXdEu5WA", "_version"=&gt;2, "result"=&gt;"deleted", "_shards"=&gt;{"total"=&gt;2, "successful"=&gt;1, "failed"=&gt;0}, "_seq_no"=&gt;25, "_primary_term"=&gt;1}

puts 'Deleting index'
response = client.indices.delete(index: index)
puts response
# Deleting index
# {"acknowledged"=&gt;true}<h2>Ruby 앱을 Elasticsearch로 마이그레이션하기</h2><p>첫 번째 단계는 젬파일에 <code>elasticsearch-ruby</code> 을 추가하는 것입니다. <code>bundle install</code> 을 실행하면 Elasticsearch Ruby 클라이언트 젬이 설치됩니다. 완전히 마이그레이션하기 전에 코드를 테스트하고 싶다면 처음에는 <code>opensearch-ruby</code> gem을 그대로 두면 됩니다.</p><p>다음으로 중요한 단계는 클라이언트 인스턴스화입니다. 이것은 Elasticsearch를 실행하는 방식에 따라 달라집니다. 이 예제에서 유사한 접근 방식을 유지하기 위해, 저는 <a href="https://www.elastic.co/downloads/elasticsearch">Elasticsearch 다운로드</a> 및 로컬 실행의 단계를 따르고 있습니다.</p><p><code>bin/elasticsearch</code> 을 실행하면 보안 기능이 자동으로 구성된 상태로 Elasticsearch가 시작됩니다. Elastic 사용자의 비밀번호를 복사해야 합니다(하지만 <code>bin/elasticsearch-reset-password -u elastic</code>)를 실행하여 재설정할 수 있습니다. 이 예제를 따르는 경우, 동일한 포트에서 실행되므로 Elasticsearch를 시작하기 전에 OpenSearch를 중지해야 합니다.</p><p><code>example_code.rb</code> 의 시작 부분에서 OpenSearch 클라이언트 인스턴스화를 주석 처리하고 Elasticsearch 클라이언트에 대한 인스턴스화를 추가했습니다:</p># require 'opensearch'

# client = OpenSearch::Client.new(
#   host: 'https://localhost:9200',
#   user: 'admin',
#   password: ENV['OPENSEARCH_INITIAL_ADMIN_PASSWORD']
#   transport_options: { ssl: { verify: false } }
# )

require 'elasticsearch'

client = Elasticsearch::Client.new(
  host: 'https://localhost:9200',
  user: ENV['ELASTICSEARCH_USER'],
  password: ENV['ELASTICSEARCH_PASSWORD'],
  transport_options: { ssl: { verify: false } }
)<p>보시다시피 이 테스트 시나리오의 코드는 거의 동일합니다. Elasticsearch의 배포와 연결 및 인증 방법에 따라 달라집니다. 여기에서도 보안과 관련하여 OpenSearch와 동일하게 적용되며, SSL을 확인하지 않는 옵션은 테스트 목적으로만 사용되며 운영 환경에서는 사용해서는 안 됩니다.</p><p>클라이언트가 설정되면 코드를 다시 실행합니다: <code>bundle exec ruby example_code.rb</code>. 그리고 모든 것이 작동합니다!</p><h2>마이그레이션 문제 디버깅</h2><p>애플리케이션에서 사용 중인 API에 따라, OpenSearch의 API가 서로 다른 경우 Elasticsearch에서 코드를 실행할 때 오류가 발생할 수 있습니다. <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html">REST API 문서는</a> API 사용 방법에 대한 자세한 정보를 얻기 위한 필수 참고 자료입니다. 사용 중인 Elasticsearch 버전에 대한 설명서를 확인하시기 바랍니다. <a href="https://rubydoc.info/gems/elasticsearch-api"><code>Elasticsearch::API</code></a> 참조를 참조할 수도 있습니다.</p><p>Elasticsearch에서 발생할 수 있는 몇 가지 오류는 다음과 같습니다:</p><ul><li><p><code>ArgumentError: Required argument '&lt;ARGUMENT&gt;' missing</code> - 클라이언트 오류이며 요청에 필수 매개변수가 누락된 경우 발생합니다.</p></li><li><p><code>Elastic::Transport::Transport::Errors::BadRequest: [400] {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"request [/example/_doc] contains unrecognized parameter: [test]"}]...</code> 이 오류는 Elasticsearch에서 발생하며 클라이언트 코드가 사용 중인 API에 대해 Elasticsearch가 인식하지 못하는 매개 변수를 사용하고 있음을 의미합니다.</p></li></ul><p>Elasticsearch 클라이언트는 서버에서 전송한 자세한 오류 메시지와 함께 Elasticsearch에서 오류를 발생시킵니다. 따라서 지원되지 않는 매개변수나 엔드포인트의 경우에도 오류를 통해 무엇이 다른지 알 수 있습니다.</p><h2>결론</h2><p>이 예제 코드에서 보여드렸듯이, Ruby 앱을 OpenSearch에서 Elasticsearch로 마이그레이션하는 것은 Ruby 측면에서 볼 때 그리 복잡하지 않습니다. 검색 엔진 간의 버전 관리 및 잠재적으로 서로 다른 API를 알고 있어야 합니다. 그러나 가장 일반적인 작업의 경우 클라이언트를 마이그레이션할 때 주로 변경되는 부분은 인스턴스화입니다. 이 점에서 둘은 비슷하지만 호스트와 자격 증명이 정의되는 방식은 스택이 배포되는 방식에 따라 다릅니다. 클라이언트가 설정되고 Elasticsearch에 연결되는 것을 확인하면 OpenSearch 클라이언트를 Elasticsearch 클라이언트로 원활하게 교체할 수 있습니다.
</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ruby-opensearch-elasticsearch-migration</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ruby-opensearch-elasticsearch-migration</guid>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Fernando Briano]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7f2ce1fb5cbf7d70/6a17e1dd148009bc02b486af/47756f629737d47c4430860ea23366a8d24c90d9-1280x720.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 13 Dec 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>