<?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/cn/search-labs/author/fernando-briano</link>
    </image>
    <link>https://www.elastic.co/cn/search-labs/author/fernando-briano</link>
    <atom:link href="https://www.elastic.co/cn/search-labs/rss/author/fernando-briano.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[cn]]></language>
    <lastBuildDate>Wed, 23 Sep 2026 09:50:57 GMT</lastBuildDate>
  <item>
    <title><![CDATA[介绍用于 Elasticsearch Ruby 客户端的 ES|QL 查询生成器]]></title>
    <description><![CDATA[了解如何使用最近发布的用于 Elasticsearch Ruby 客户端的 ES|QL 查询生成器。这是一款使用 Ruby 代码更轻松地构建 ES|QL 查询的工具。]]></description>
    <content:encoded><![CDATA[<p>我们最近发布了<a href="https://github.com/elastic/esql-ruby/"><code>elastic-esql</code></a> ，这是一个根据 Apache 2 许可证发布的 Ruby gem。有了这个 gem，你就可以用惯用的 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> ) 来逐步处理数据。该 gem 使用 Ruby 函数，你可以将这些函数链入原始对象，以建立更复杂的查询：</p><p><strong>ESQL：</strong></p><p><strong>鲁比</strong></p>Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending<h2>安装</h2><p>该 gem 可通过以下方式从 RubyGems 安装：</p>gem install elastic-esql<p>或者将其添加到项目的 Gemfile 中：</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> 方法中，gem 将代码转换为 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>该工具提供了将额外步骤链入 ES|QL 函数的便捷方法，如<code>enrich</code> 和<code>sort</code> 。一旦在<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>在 Ruby 客户端使用 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 Helper 结合使用，<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>该 gem 被设计为一个独立工具，用于以惯用方式构建 ES|QL 查询。它没有运行时依赖性，可以与官方 Elasticsearch Ruby 客户端一起使用，也可以单独使用。</p><p>生成的查询可在<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-query"><code>esql.query</code></a> API 中使用，无论应用程序以何种方式与 Elasticsearch API 交互（无论是否使用 Ruby）。使用<code>elastic-esql</code> 创建查询后，生成的字符串就可以作为<code>query</code> 请求正文中的参数发送给应用程序接口。 </p><p>我曾写过一篇关于<a href="https://www.elastic.co/search-labs/blog/elasticsearch-ruby-tools">将 Elasticsearch 与流行的 Ruby 工具结合使用的</a>文章。该 gem 可与任何流行的 Ruby 工具一起使用，以通过 ES|QL 查询 Elasticsearch。</p><h2>结论</h2><p>该库正在积极开发中，最终的应用程序接口尚未完成。目前发布的是技术预览版。如果您对当前的应用程序接口或一般使用方法有任何反馈，请随时<a href="https://github.com/elastic/esql-ruby/issues">打开新问题</a>。有关 Ruby 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[如何将 Ruby 应用程序从 OpenSearch 迁移到 Elasticsearch]]></title>
    <description><![CDATA[将 Ruby 代码库从 OpenSearch 客户端迁移到 Elasticsearch 客户端的指南。]]></description>
    <content:encoded><![CDATA[<p>OpenSearch Ruby 客户端是从版本<code>7.x</code> 的 Elasticsearch Ruby 客户端分叉而来，因此代码库相对相似。这意味着在将 Ruby 代码库从 OpenSearch 迁移到 Elasticsearch 时，各客户端库中的代码看起来会非常熟悉。在这篇博文中，我将展示一个使用 OpenSearch 的 Ruby 应用程序示例，以及将代码迁移到 Elasticsearch 的步骤。</p><p>这两个客户端都是根据流行的 Apache License 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> ，可以使用版本为<code>8.17.x</code> 的 Ruby gem。</p><p>OpenSearch 源自 Elasticsearch 7.10.2。因此，应用程序接口可能已经发生了变化，不同的功能可以在其中任何一个上使用。但这不在本篇文章的讨论范围内，我只想在一个示例应用程序中了解最常见的操作。</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/">从 tar 包中安装 OpenSearch</a>。下载并解压 tar 包后，我需要设置一个初始管理员密码，稍后将使用该密码实例化客户端。</p><p>我创建了一个带有<code>Gemfile</code> 的目录，看起来像这样：</p>source 'https://rubygems.org'

gem 'opensearch-ruby'<p>运行<code>bundle install</code> 后，我的项目安装了 gem。这就安装了<code>3.4.0</code> 版本的 opensearch-ruby，而我运行的 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>使用<code>cluster.health</code> API 是确保客户端连接 OpenSearch 的一个简单 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>第一步是在 Gemfile 中添加<code>elasticsearch-ruby</code> 。运行<code>bundle install</code> 后，Elasticsearch Ruby 客户端 gem 将被安装。如果想在完全迁移前测试代码，可以先保留<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 会自动配置安全功能。确保复制了弹性用户的密码（但可以通过运行<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 的不同，您在针对 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，这意味着客户端代码使用了 Elasticsearch 无法识别的 API 参数。</p></li></ul><p>Elasticsearch 客户端会从 Elasticsearch 引发错误，并附带服务器发送的详细错误信息。因此，即使是不支持的参数或端点，错误也会告诉你有什么不同。</p><h2>结论</h2><p>正如我们在本示例代码中演示的那样，从 Ruby 端将 Ruby 应用程序从 OpenSearch 迁移到 Elasticsearch 并不复杂。您需要了解搜索引擎之间的版本和任何潜在的不同应用程序接口。但就最常见的操作而言，迁移客户端时的主要变化在于实例化。它们在这方面都很相似，但主机和凭证的定义方式因堆栈的部署方式而异。一旦设置好客户端，并验证它连接到 Elasticsearch，就可以用 Elasticsearch 客户端无缝替换 OpenSearch 客户端。
</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>