<?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[Ruby - 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[Ruby - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/de/search-labs/blog/category/ruby-programming</link>
    </image>
    <link>https://www.elastic.co/de/search-labs/blog/category/ruby-programming</link>
    <atom:link href="https://www.elastic.co/de/search-labs/rss/category/ruby-programming.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[de]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 03:02:22 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Einführung des ES|QL-Abfragegenerators für den Elasticsearch Ruby Client]]></title>
    <description><![CDATA[Lernen Sie, wie Sie den kürzlich veröffentlichten ES|QL-Abfragegenerator für den Elasticsearch Ruby Client verwenden. Ein Tool, um ES|QL-Abfragen mit Ruby-Code einfacher zu erstellen.]]></description>
    <content:encoded><![CDATA[<p>Wir haben kürzlich <a href="https://github.com/elastic/esql-ruby/"><code>elastic-esql</code></a> veröffentlicht, ein Ruby-Gem, das unter der Apache 2-Lizenz veröffentlicht wurde. Dieses Juwel ermöglicht es Ihnen, Elastic <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql">ES|QL-</a> Abfragen in idiomatischem Ruby zu erstellen, die Sie dann mit der ES|QL-Abfrage-API verwenden können. ES|QL ermöglicht es Entwicklern, in Elasticsearch gespeicherte Daten mittels Abfragen zu filtern, zu transformieren und zu analysieren. Es verwendet "Pipes" ( <code>|</code> ), um die Daten schrittweise zu verarbeiten. Das Gem verwendet stattdessen Ruby-Funktionen, die Sie an das ursprüngliche Objekt anhängen können, um komplexere Abfragen zu erstellen:</p><p><strong>ESQL:</strong></p><p><strong>Rubin:</strong></p>Elastic::ESQL.from('sample_data').limit(2).sort('@timestamp').descending<h2>Installation</h2><p>Das Gem kann über RubyGems installiert werden mit:</p>gem install elastic-esql<p>Alternativ kann es der Gemfile-Datei eines Projekts hinzugefügt werden:</p>gem 'elastic-esql'<h2>Verwendung</h2><p>Sie können entweder eine vollständige Abfrage auf einmal erstellen oder ein Abfrageobjekt mit einem Quellbefehl wie <code>from</code> oder <code>row</code> erstellen und dann ES|QL-Methoden verketten, um darauf aufzubauen.</p>query = Elastic::ESQL.from('sample_data')
query.limit(2).sort('@timestamp')<p>Das Gem übersetzt den Code in ES|QL für die <code>to_s</code> -Methode, sodass es die ES|QL-Abfrage zurückgibt, wenn sie ausgegeben oder als String gecastet wird:</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>Sie können ein Abfrageobjekt instanziieren und seinen Anfangszustand verändern, indem Sie die <code>!</code> -Äquivalente jeder Funktion verwenden:</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>Das Tool bietet bequeme Möglichkeiten, zusätzliche Schritte an eine ES|QL-Funktion anzuhängen, wie z. B. <code>enrich</code> und <code>sort</code>. Sobald Sie <code>enrich</code> auf einem <code>Elastic::ESQL</code> -Objekt aufgerufen haben, können Sie <code>on</code> und <code>with</code> daran anhängen:</p>esql.enrich!('policy').on('a').with({ name: 'language_name' })<p>Sie können auch <code>desc</code>, <code>asc</code>, <code>nulls_first</code> und <code>nulls_last</code> an Ihre Abfrage anhängen, nachdem Sie <code>sort</code> verwendet haben:</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 unterstützt auch benutzerdefinierte Zeichenketten, falls Sie die ES|QL-Abfrage selbst schreiben oder eine Funktion nutzen möchten, die noch nicht in die Bibliothek aufgenommen wurde. <code>custom</code> wird die Zeichenketten am Ende der Abfrage zusammenfügen. Die Zeichen werden beim Senden an die Funktion hinzugefügt, ohne dabei Pipe-Zeichen einzufügen. Sie werden durch ein Leerzeichen mit dem Rest der Anfrage verbunden.</p>esql = Elastic::ESQL.from('sample_data')
esql.custom('| MY_VALUE = "test value"').to_s
# =&gt; 'FROM sample_data | MY_VALUE = "test value"'<p>Sie können auch <code>custom</code> -Funktionen verketten:</p>esql.custom('| MY_VALUE = "test value"').custom('| ANOTHER, VALUE')
'FROM sample_data | MY_VALUE = "test value" | ANOTHER, VALUE'<h2>Verwendung des ES|QL Query Builders mit dem Ruby-Client</h2><p>Sie können den Query Builder direkt mit <a href="https://github.com/elastic/elasticsearch-ruby">elasticsearch-ruby</a> und der <code>esql.query</code> API verwenden, indem Sie das Query-Objekt senden:</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>Sie können es auch mit dem ES|QL-Helper des Elasticsearch Ruby-Clients verwenden. <a href="https://www.elastic.co/search-labs/blog/esql-ruby-helper-elasticsearch">Weitere Informationen finden Sie hier</a>:</p>require 'elasticsearch/helpers/esql_helper'

Elasticsearch::Helpers::ESQLHelper.query(client, query)<h2>Als eigenständiges Werkzeug</h2><p>Das Gem ist als eigenständiges Werkzeug konzipiert, um ES|QL-Abfragen auf idiomatische Weise zu erstellen. Es hat keine Laufzeitabhängigkeiten; Sie können es mit dem offiziellen Elasticsearch Ruby-Client oder auch eigenständig verwenden.</p><p>Die generierte Abfrage kann mit der <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-query"><code>esql.query</code></a> API auf jede Art und Weise verwendet werden, wie eine Anwendung mit der Elasticsearch API interagiert (Ruby oder nicht). Sobald eine Abfrage mit <code>elastic-esql</code> erstellt wurde, kann die generierte Zeichenkette als Parameter <code>query</code> im Anfragetext an die API gesendet werden. </p><p>Ich habe bereits über <a href="https://www.elastic.co/search-labs/blog/elasticsearch-ruby-tools">die Verwendung von Elasticsearch mit gängigen Ruby-Tools</a> geschrieben. Dieses Gem kann mit allen gängigen Ruby-Tools verwendet werden, um Elasticsearch mit ES|QL abzufragen.</p><h2>Fazit</h2><p>Diese Bibliothek befindet sich in aktiver Entwicklung, und die endgültige API ist noch nicht fertiggestellt. Es ist aktuell als technische Vorschauversion veröffentlicht. Sollten Sie Feedback zur aktuellen API oder zur allgemeinen Nutzung haben, zögern Sie bitte nicht <a href="https://github.com/elastic/esql-ruby/issues">, ein neues Issue zu eröffnen</a>. Weitere Informationen zum Ruby ES|QL Query Builder finden Sie in <a href="https://github.com/elastic/esql-ruby/?tab=readme-ov-file#ruby-esql-query-builder">der README-Datei</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>
    <pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Ruby-Skripting in Logstash]]></title>
    <description><![CDATA[Erfahren Sie mehr über das Logstash Ruby Filter-Plugin für die erweiterte Datentransformation in Ihrer Logstash-Pipeline.]]></description>
    <content:encoded><![CDATA[<p>Logstash ist eine Datenverarbeitungspipeline, die Daten aus verschiedenen Quellen aufnimmt, transformiert und an die von Ihnen gewählten Ziele sendet. Filter-Plugins sind für diesen Prozess unerlässlich; sie führen spezifische Operationen an Ihren Daten durch, während diese die Datenpipeline durchlaufen.</p><p>Logstash enthält mehrere integrierte Filter für häufige Aufgaben wie das Parsen, Anreichern und Modifizieren von Daten. Manchmal stößt man jedoch auf Szenarien, die eine benutzerdefinierte Logik erfordern, die über das hinausgeht, was diese Standardfilter bieten können. Hier kommt das <a href="https://www.elastic.co/docs/reference/logstash/plugins/plugins-filters-ruby">Ruby-Filter-Plugin</a> ins Spiel.</p><p><strong>Mit dem Ruby-Filter-Plugin können Sie benutzerdefinierten Ruby-Code direkt in Ihrer Logstash-Pipeline ausführen.</strong> Wenn Standardfilter nicht ausreichen, ermöglicht Ihnen der Ruby-Filter die Durchführung komplexer Datentransformationen, die Implementierung benutzerdefinierter Geschäftslogik oder die Integration mit externen Systemen.</p><p>In diesem Blogbeitrag zeigen wir Ihnen, wie Sie Ruby-Filter verwenden – von den Grundlagen bis hin zu fortgeschrittenen Anwendungsfällen.</p><h2>Wann sollte man den Ruby-Filter verwenden?</h2><p>Als beratender Architekt bei Elastic sehe ich oft, dass Kunden Logstash für die Datenverarbeitungspipeline verwenden, obwohl es heutzutage keine hochmoderne Datenverarbeitungs-Engine mehr ist. Bei komplexen Datenmanipulationen oder benutzerdefinierter Logik stoßen sie häufig an die Grenzen von Standardfiltern. In diesen Fällen kann der Ruby-Filter dazu beitragen, diese Herausforderungen zu bewältigen.</p><p>Der Ruby-Filter ist nützlich, wenn die Standard-Logstash-Filter Ihre spezifischen Anforderungen nicht erfüllen können. Hier einige typische Anwendungsfälle:</p><ul><li><p><strong>Tief verschachtelte Datenmanipulation</strong>: Komplexe JSON-Strukturen, Arrays innerhalb von Arrays modifizieren oder Daten dynamisch anhand ihres Inhalts umstrukturieren.</p></li><li><p><strong>Erweiterte Stringverarbeitung</strong>: Strukturierte Daten aus unstrukturiertem Text analysieren und extrahieren</p></li><li><p><strong>Implementierung komplexer Geschäftslogik</strong>: Erstellen benutzerdefinierter Transformationen, die bedingte Logik, Schleifen oder komplexe Berechnungen erfordern.</p></li></ul><h2>Grundlegende Verwendung</h2><p>Beginnen wir mit einem einfachen Beispiel, um zu verstehen, wie der Ruby-Filter funktioniert.</p><h3>Konfigurieren des Ruby-Filters</h3><p>Wenn Sie eine Logstash-Pipeline erstellen, sollten Sie die Konfigurationsdatei im Verzeichnis <code>/etc/logstash/conf.d</code> ablegen. Alternativ können Sie die Option <code>-f</code> verwenden, um beim manuellen Starten von Logstash den Pfad zur Konfigurationsdatei anzugeben, sodass Sie problemlos mit Ihren Pipelines experimentieren können.</p>$ ./bin/logstash -f /path/to/your_pipeline.conf<p>Die Konfigurationsdatei sollte die Dateiendung <code>.conf</code> haben.</p><p>Um den Ruby-Filter zu verwenden, definieren Sie einen <code>ruby</code> -Filter im Filterabschnitt Ihrer Logstash-Pipeline-Konfigurationsdatei (*.conf). Hier ein einfaches Beispiel:</p>filter {
  ruby {
    code =&gt; "
      event.set('new_field', 'Hello from Ruby!')
    "
  }
}<p>Dieser Inline-Ruby-Filter definiert eine Ruby-Filterinstanz innerhalb Ihrer Logstash-Konfiguration. Der Parameter <code>code</code> stellt das Inline-Ruby-Skript bereit, das Logstash für jedes von diesem Filter verarbeitete Ereignis ausführt. Innerhalb dieses Skripts gibt es eine <code>event</code> Variable, die das Ereignis selbst repräsentiert. Das Ereignisobjekt enthält die Originaldaten, die an Logstash gesendet wurden, sowie alle zusätzlichen Felder, die während der Filterphasen von Logstash erstellt wurden. Sie können auf diese Felder über die Logstash Event API zugreifen, zum Beispiel über <code>event.get()</code> und <code>event.set()</code>. In diesem Beispielcode hat <code>event.set('new_field', 'Hello from Ruby!')</code> ein neues Feld mit dem Namen <code>new_field</code> auf den Zeichenkettenwert <code>Hello from Ruby!</code> gesetzt. Sie können bei Bedarf weiteren Code in diesen <code>code</code> -Block einfügen.</p><p>Beachten Sie, dass dieses <code>event</code> -Objekt kein gewöhnliches Ruby-Hash-Objekt ist, obwohl es als Datencontainer vom Typ Schlüssel-Wert fungiert. In <a href="https://www.elastic.co/docs/reference/logstash/event-api">dieser offiziellen Dokumentation</a> erfahren Sie mehr über die Event-API.</p><h3>Ruby-Skript auslagern</h3><p>Für einfache Transformationen ist Inline-Ruby-Code praktisch. Für komplexe Logik oder wiederverwendbare Funktionen empfiehlt es sich jedoch, den Code in ein externes Ruby-Skript auszulagern. Dies verbessert die Wartbarkeit und sorgt für eine saubere Logstash-Pipeline-Konfiguration.</p><p>Zuerst erstellen Sie ein Ruby-Skript und speichern es unter dem Namen <code>my_ruby_script.rb</code>. Das Skript muss eine <code>filter</code> Methode definieren, die das Ereignis verarbeitet. Es benötigt ein Ereignisobjekt als Argument, das das aktuell verarbeitete Ereignis repräsentiert. Die Methode <code>filter</code> muss ein Array von Ereignissen zurückgeben, die ausgelöst werden sollen. Um das Ereignis zu verwerfen, geben Sie ein leeres Array zurück.</p><p>Das folgende Skript liest beispielsweise das Feld <code>message</code> , berechnet seine Länge und speichert das Ergebnis in einem neuen Feld namens <code>message_length</code>.</p>def register(params)
  # This method is called when the plugin is loaded.
  # You can use it to initialize any instance variables or perform setup tasks.
end

def filter(event)
  message = event.get('message')

  if message
    event.set('message_length', message.length)
  end

  return [event]
end<p>Als Nächstes muss die Ruby-Filterkonfiguration so eingestellt werden, dass sie mit der Option <code>path</code> auf das Skript verweist. Dies weist Logstash an, das externe Skript zu laden und auszuführen. Bei der Verwendung externer Skripte muss sichergestellt werden, dass die Datei existiert und über die korrekten Berechtigungen verfügt.</p>filter {
  ruby {
    path =&gt; "/path/to/my_ruby_script.rb"
  }
}<p>Nun wird jedes Ereignis an die Methode <code>filter</code> in <code>my_ruby_script.rb</code> übergeben und von dieser verarbeitet.</p><p>Dieser Ansatz hilft Ihnen, komplexe Logik effektiver zu handhaben und erleichtert so das Testen, Debuggen und Wiederverwenden Ihres Ruby-Codes.</p><h2>Erweiterte Nutzung</h2><p>In diesem Abschnitt werden wir einige fortgeschrittene Beispiele für die Verwendung des Ruby-Filters in Logstash untersuchen. Anhand dieser Beispiele wird demonstriert, wie man Datentransformationen durchführt, Ereignisse anreichert und benutzerdefinierte Logik mit Ruby implementiert.</p><h3>Manipulation verschachtelter Datenstrukturen</h3><p>Ein Logstash-Ereignis ist die zentrale Datenstruktur, die von Logstash verarbeitet wird. Es kann verschiedene Felder enthalten, darunter auch verschachtelte Datenstrukturen wie Arrays und Hashes. Der Ruby-Filter ermöglicht Ihnen die einfache Bearbeitung dieser verschachtelten Strukturen.</p><p>Der Ruby-Filter kann verschachtelte Datenstrukturen wie Hashes und Arrays verarbeiten und ermöglicht es Ihnen, Felder innerhalb dieser Strukturen zu ändern oder hinzuzufügen. Dies ist hilfreich beim Umgang mit komplexen Datenformaten wie JSON.</p>input {
  generator {
    lines =&gt; [
      '{"nested": {"key1": "value1", "key2": "value2"}}'
    ]
    count =&gt; 1
    codec =&gt; "json"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  ruby {
    code =&gt; "
      nested_data = event.get('nested')

      if nested_data.is_a?(Hash)
        nested_data['key3'] = 'value3'
        event.set('nested', nested_data)
      end
    "
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Dieses Beispiel enthält ein verschachteltes JSON-Objekt in den Eingabedaten. Der Ruby-Filter modifiziert die verschachtelten Daten, indem er ein neues Schlüssel-Wert-Paar hinzufügt. Diese Art der Manipulation von verschachtelten Daten ist mit den Standard-Logstash-Filtern nicht möglich, wodurch der Ruby-Filter eine praktische Option für komplexe Datenstrukturen darstellt.</p><h3>Teile ein einzelnes Ereignis in mehrere Ereignisse auf</h3><p>Ruby-Filter können auch verwendet werden, um ein einzelnes Ereignis in mehrere Ereignisse aufzuteilen. Dies ist nützlich, wenn Sie ein einzelnes Ereignis haben, das ein Array von Elementen enthält, und Sie für jedes Element ein separates Ereignis erstellen möchten.</p><p>Beachten Sie, dass weder die Ingest-Pipeline von Elasticsearch noch die Prozessoren von Beats/Elastic Agent das Aufteilen von Ereignissen unterstützen. Dies ist einer der überzeugendsten Anwendungsfälle für Logstash.</p><h4>Mit geteiltem Filter</h4><p>Mit dem Filter <code>split</code> können Sie ein Ereignis anhand eines bestimmten Feldes in mehrere Ereignisse aufteilen. Wenn Sie jedoch während der Aufteilung zusätzliche Transformationen oder Logik durchführen müssen, können Sie den Ruby-Filter in Kombination mit dem Split-Filter verwenden.</p><p>Im folgenden Beispiel haben wir einen RSS-Feed als einzeiligen XML-Text. Es enthält mehrere <code>&lt;item&gt;</code> -Elemente. Der Ruby-Filter dient dazu, die <code>&lt;item&gt;</code> -Elemente aus dem XML zu extrahieren und in einem neuen Feld namens <code>items</code> zu speichern. Anschließend wird der Split-Filter verwendet, um das Ereignis anhand des Feldes <code>items</code> in mehrere Ereignisse aufzuteilen.</p>input {
  generator {
    lines =&gt; [
      '&lt;rss version="2.0"&gt;&lt;channel&gt;&lt;title&gt;Sample RSS&lt;/title&gt;&lt;item&gt;&lt;title&gt;Article 1&lt;/title&gt;&lt;link&gt;http://example.com/1&lt;/link&gt;&lt;description&gt;Desc 1&lt;/description&gt;&lt;/item&gt;&lt;item&gt;&lt;title&gt;Article 2&lt;/title&gt;&lt;link&gt;http://example.com/2&lt;/link&gt;&lt;description&gt;Desc 2&lt;/description&gt;&lt;/item&gt;&lt;/channel&gt;&lt;/rss&gt;'
    ]
    count =&gt; 1
    codec =&gt; "plain"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "event.set('items', event.get('[rss][channel][item]')) if event.get('[rss][channel][item]')"
  }
  split {
    field =&gt; "items"
  }
  ruby {
    code =&gt; "
      item = event.get('items')
      event.set('title', item['title']) if item['title']
      event.set('link', item['link']) if item['link']
      event.set('description', item['description']) if item['description']
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Die Ausgabe lautet wie folgt:</p>{
          "title" =&gt; "Article 1",
           "link" =&gt; "http://example.com/1",
    "description" =&gt; "Desc 1"
}
{
          "title" =&gt; "Article 2",
           "link" =&gt; "http://example.com/2",
    "description" =&gt; "Desc 2"
}<p>Wie Sie vielleicht bemerkt haben, ist der <code>ruby</code> -Filter in diesem Fall nicht unbedingt erforderlich. Mit dem Filter <code>split</code> kann das Ereignis anhand des Feldes <code>items</code> in mehrere Ereignisse aufgeteilt werden, und mit dem Filter <code>mutate</code> können unnötige Felder entfernt werden. Wenn Sie jedoch während der Aufteilung zusätzliche Transformationen oder Logik durchführen müssen, können Sie den Ruby-Filter verwenden.</p><h4>Verwenden Sie das Inline-Ruby-Skript.</h4><p>Sie können auch ein Inline-Ruby-Skript verwenden, um ein einzelnes Ereignis in mehrere Ereignisse aufzuteilen, indem Sie die Methode <code>event.clone</code> und die Methode <code>new_event_block variable</code> verwenden, z. B. <code>new_event_block.call(new_event)</code>. Dies ermöglicht es Ihnen, neue Ereignisse auf Basis des ursprünglichen Ereignisses zu erstellen und dabei dessen Daten zu erhalten.</p><p>Hier ist ein Beispiel, wie man den Ruby-Filter verwendet, um ein einzelnes Ereignis in mehrere Ereignisse aufzuteilen. Eingabe und Ausgabe sind die gleichen wie im vorherigen Beispiel.</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "
      items = event.get('[rss][channel][item]')
      if items.is_a?(Array)
        items.each do |item|
          new_event = event.clone
          new_event.set('title', item['title'])
          new_event.set('link', item['link'])
          new_event.set('description', item['description'])
          new_event_block.call new_event
        end
        event.cancel
      elsif items.is_a?(Hash)
        event.set('title', items['title'])
        event.set('link', items['link'])
        event.set('description', items['description'])
      end
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<h4>Externes Ruby-Skript verwenden</h4><p>Alternativ können Sie ein externes Ruby-Skript verwenden, um ein einzelnes Ereignis in mehrere Ereignisse aufzuteilen.</p><p>Konfigurationsdatei:</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    path =&gt; "path/to/ruby/split_event.rb"
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<p>Das Ruby-Skript muss als <code>split_event.rb</code> externalisiert werden:</p>def filter(event)
  items = event.get('[rss][channel][item]')
  events = []
  if items.is_a?(Array)
    items.each do |item|
      new_event = event.clone
      new_event.set('title', item['title'])
      new_event.set('link', item['link'])
      new_event.set('description', item['description'])
      events &lt;&lt; new_event
    end
    return events
  elsif items.is_a?(Hash)
    event.set('title', items['title'])
    event.set('link', items['link'])
    event.set('description', items['description'])
    return [event]
  else
    return []
  end
end<p>Denken Sie daran, dass die Methode <code>filter</code> ein Array von Ereignissen zurückgeben muss. Sie können mehrere Ereignisse zurückgeben, indem Sie ein eingehendes Ereignisobjekt klonen und die Ergebnisse dem Array hinzufügen, oder Sie können ein einzelnes Ereignis als Array mit einem Element zurückgeben.</p>return events
# or
# return [event]<p>Dies ermöglicht es Ihnen, ein einzelnes Ereignis in mehrere Ereignisse aufzuteilen.</p><h3>Führe externe Befehle aus und analysiere deren Ausgabe.</h3><p>Das Logstash exec input-Plugin ermöglicht die Ausführung externer Befehle, deren Ausgabe ein Logstash-Ereignis darstellt. Die Ausgabe des Befehls wird im Feld <code>message</code> des Ereignisses gespeichert.</p><p>Normalerweise sind die Ausgaben von Systembefehlen für Menschen lesbar, aber nicht als JSON oder in anderen Formaten strukturiert, die Logstash problemlos parsen kann. Um dies zu handhaben, können Sie den Ruby-Filter verwenden, um die Ausgabe zu analysieren und die Informationen daraus zu extrahieren.</p><p>Hier ist ein Beispiel für die Verwendung des <code>exec</code> -Input-Plugins zur Ausführung des <code>ps -ef</code> -Befehls, der alle laufenden Prozesse auf einem Unix-ähnlichen System auflistet. Die Ausgabe wird vom Ruby-Filter analysiert, um relevante Informationen über jeden Prozess zu extrahieren.</p>input {
  exec {
    command =&gt; "ps -ef"
    interval =&gt; 60
  }
}

filter {
  ruby {
    code =&gt; '
      processes = []
      lines = event.get("message").split("\n")  
      lines.each_with_index do |line, index|
        # Skip header line and empty lines
        next if index == 0 || line.strip.empty?
        entry = nil
        
        # Use regex to match the ps -ef output format more flexibly
        # This pattern accounts for variable spacing and different time formats
        if line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\d:]+\.?\d*)\s+(.+)$/
          uid, pid, ppid, c, stime, tty, time, cmd = $1, $2, $3, $4, $5, $6, $7, $8
          
          entry = {
            "UID" =&gt; uid,
            "PID" =&gt; pid,
            "PPID" =&gt; ppid,
            "C" =&gt; c,
            "STIME" =&gt; stime,
            "TTY" =&gt; tty,
            "TIME" =&gt; time,
            "CMD" =&gt; cmd.strip
          }
        elsif line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/
          # Fallback pattern for lines that might not match the exact format
          # Split the remaining part more carefully
          uid, pid, ppid, c, remainder = $1, $2, $3, $4, $5
          
          # Split remainder into STIME, TTY, TIME, CMD
          parts = remainder.strip.split(/\s+/, 4)
          if parts.length &gt;= 4
            stime, tty, time, cmd = parts[0], parts[1], parts[2], parts[3]
            
            entry = {
              "UID" =&gt; uid,
              "PID" =&gt; pid,
              "PPID" =&gt; ppid,
              "C" =&gt; c,
              "STIME" =&gt; stime,
              "TTY" =&gt; tty,
              "TIME" =&gt; time,
              "CMD" =&gt; cmd
            }
          end
        end
        if entry &amp;&amp; entry["UID"] == "0"
          original_line = line.strip
          entry["original_line"] = original_line if original_line.length &gt; 0
          processes.push(entry)
        end
      end
      event.set("processes", processes)
      event.remove("message")
      event.remove("event")
    '
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Dieses Beispiel verwendet das <code>exec</code> -Input-Plugin, um den <code>ps -ef</code> -Befehl alle 60 Sekunden auszuführen. Der Ruby-Filter verarbeitet die Ausgabe und extrahiert relevante Felder wie UID, PID, PPID, CPU-Auslastung (C), Startzeit (STIME), TTY, Gesamt-CPU-Zeit (TIME) und den ausgeführten Befehl (CMD). Auf meiner macOS-Umgebung funktioniert es einwandfrei, aber möglicherweise müssen Sie die Regex-Muster an das Ausgabeformat des Befehls <code>ps -ef</code> auf Ihrem System anpassen.</p><h3>Verwenden Sie integrierte Bibliotheken</h3><p>Das Ruby-Filter-Plugin ermöglicht die Verwendung integrierter Ruby-Bibliotheken, was für verschiedene Aufgaben sehr nützlich sein kann. Beispielsweise können Sie die <code>json</code> -Bibliothek zum Parsen von JSON-Zeichenketten oder die <code>date</code> -Bibliothek zum Bearbeiten von Datumsangaben verwenden.</p><p>Hier ist ein Beispiel für die Verwendung der <code>json</code> -Bibliothek zum Parsen einer in einem Feld gespeicherten JSON-Zeichenkette:</p>require 'json'

def filter(event)
  json_string = event.get('message')
  parsed_json = JSON.parse(json_string)
  event.set('parsed_json', parsed_json)
  return [event]
end<p>Um zu vermeiden, dass die Bibliothek jedes Mal neu geladen werden muss, sollten Sie Ihren Ruby-Code auslagern, damit Sie die <code>require</code> -Anweisung am Anfang Ihres Ruby-Filterskripts verwenden können. Dadurch wird die Bibliothek einmalig geladen und steht Ihnen anschließend in Ihrem Skript zur Verfügung.</p><p>Um zu überprüfen, welche Bibliotheken in Ihrer Umgebung verfügbar sind, können Sie die integrierten Bibliotheken auflisten, indem Sie den folgenden Code im Ruby-Filter ausführen:</p>Gem.loaded_specs.sort_by { |name, _| name }.each do |name, spec|
  puts "#{name}: #{spec.version}"
end<p><strong>Hinweis: </strong>Die integrierten Bibliotheken werden von Logstash nicht offiziell unterstützt, und ihr Verhalten kann sich ändern oder sie sind in zukünftigen Versionen möglicherweise nicht mehr verfügbar. Die Benutzung erfolgt auf eigene Gefahr.</p><h2>Fazit</h2><p>Mit dem Logstash Ruby-Filter können Sie die Funktionen Ihrer Logstash-Pipelines anpassen und erweitern. In diesem Beitrag haben wir die Grundlagen der Verwendung des Ruby-Filters behandelt und fortgeschrittene Anwendungsbeispiele vorgestellt.</p><p>Durch die Nutzung des Ruby-Filters können Sie komplexe Datenverarbeitungsaufgaben bewältigen, die benutzerdefinierte Logik oder fortgeschrittene Manipulationen erfordern. Egal ob Sie mit verschachtelten Datenstrukturen arbeiten, Ereignisse aufteilen oder komplexen/unstrukturierten Text in strukturiertes JSON parsen und konvertieren, der Ruby-Filter bietet die Flexibilität, Ihre spezifischen Anforderungen zu erfüllen.</p><p>Wir hoffen, dass Ihnen dieser Leitfaden das Wissen und die Inspiration vermittelt hat, das volle Potenzial des Logstash Ruby-Filters auszuschöpfen. Viel Spaß beim Skripten!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</guid>
    <category><![CDATA[Index-Daten]]></category>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Dai Sugimori]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt503d18396642e73e/6a17f62aaf47b68527cde121/b1bcd63c033ccbde102c20ba3085f165f9289a71-1600x1000.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Jun 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Wie Sie Ihre Ruby-Anwendung von OpenSearch zu Elasticsearch migrieren]]></title>
    <description><![CDATA[Eine Anleitung zur Migration einer Ruby-Codebasis vom OpenSearch-Client zum Elasticsearch-Client.]]></description>
    <content:encoded><![CDATA[<p>Der OpenSearch Ruby-Client wurde in Version <code>7.x</code> vom Elasticsearch Ruby-Client abgeleitet, daher sind die Codebasen relativ ähnlich. Das bedeutet, dass beim Migrieren einer Ruby-Codebasis von OpenSearch zu Elasticsearch der Code aus den jeweiligen Clientbibliotheken sehr vertraut aussehen wird. In diesem Blogbeitrag zeige ich eine Beispiel-Ruby-Anwendung, die OpenSearch verwendet, und die Schritte zur Migration dieses Codes zu Elasticsearch.</p><p>Beide Clients werden unter der weit verbreiteten Apache-Lizenz 2.0 veröffentlicht und sind somit Open Source und freie Software. Die Lizenz von Elasticsearch wurde kürzlich aktualisiert, und der Kern von Elasticsearch und Kibana wird seit Version 8.16 unter der von der OSI genehmigten Open-Source-Lizenz AGPL veröffentlicht.</p><h2>Bei der Migration einer Ruby-Anwendung die Elasticsearch-Version berücksichtigen</h2><p>Bei der Migration ist es unter anderem zu berücksichtigen, welche Version von Elasticsearch verwendet werden soll. Wir empfehlen die Verwendung der neuesten stabilen Version, die zum Zeitpunkt der Erstellung dieses Dokuments <code>8.17.0</code> ist. Die Nebenversionen des Elasticsearch Ruby Clients orientieren sich an den Nebenversionen von Elasticsearch. Für Elasticsearch <code>8.17.x</code> können Sie also Version <code>8.17.x</code> des Ruby-Gems verwenden.</p><p>OpenSearch ist ein Fork von Elasticsearch 7.10.2. Daher können sich die APIs geändert haben und es können unterschiedliche Funktionen auf beiden Plattformen genutzt werden. Das würde jedoch den Rahmen dieses Beitrags sprengen, und ich werde mich daher nur mit den häufigsten Operationen in einer Beispielanwendung befassen.</p><p>Für Ruby on Rails können Sie den offiziellen Elasticsearch-Client oder die <a href="https://github.com/elastic/elasticsearch-rails/">Rails-Integrationsbibliotheken</a> verwenden. Wir empfehlen, auf die jeweils neueste stabile Version von Elasticsearch und des Clients zu migrieren. Die Gem-Version <code>elasticsearch-rails</code> <code>8.0.0</code> unterstützt Rails <code>6.1</code>, <code>7.0</code> und <code>7.1</code> sowie Elasticsearch <code>8.x</code>.</p><h2>Der Code</h2><p>In diesem Beispiel bin ich den Schritten zur <a href="https://opensearch.org/docs/latest/install-and-configure/install-opensearch/tar/">Installation von OpenSearch aus einem Tarball</a> gefolgt. Nach dem Herunterladen und Entpacken des Tarballs musste ich ein anfängliches Administratorpasswort festlegen, das ich später zur Instanziierung des Clients verwenden werde.</p><p>Ich habe ein Verzeichnis mit <code>Gemfile</code> erstellt, das folgendermaßen aussieht:</p>source 'https://rubygems.org'

gem 'opensearch-ruby'<p>Nach dem Ausführen von <code>bundle install</code> ist das Gem für mein Projekt installiert. Es wurde opensearch-ruby Version <code>3.4.0</code> installiert, und die Version von OpenSearch, die ich verwende, ist <code>2.18.0</code>. Ich habe den Code in einer <code>example_code.rb</code> -Datei im selben Verzeichnis geschrieben. Der initiale Code in dieser Datei ist die Instanziierung eines OpenSearch-Clients:</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>Der Parameter „Transportoption <code>ssl: { verify: false}</code> wird gemäß Benutzerhandbuch übergeben, um das Testen zu vereinfachen. Im Produktionsbetrieb sollte dies je nach Bereitstellung von OpenSearch konfiguriert werden.</p><p>Seit Version 2.12.0 von OpenSearch muss die Umgebungsvariable <code>OPENSEARCH_INITIAL_ADMIN_PASSWORD</code> beim Ausführen des Installationsskripts auf ein sicheres Passwort gesetzt werden. Nachdem ich die Schritte zur Installation von OpenSearch aus einem Tarball befolgt hatte, exportierte ich die Variable in meiner Konsole und sie steht nun meinem Ruby-Skript zur Verfügung.</p><p>Eine einfache API, um sicherzustellen, dass der Client eine Verbindung zu OpenSearch herstellt, verwendet die <code>cluster.health</code> API:</p>puts 'HEALTH:'
pp client.cluster.health<p>Und es funktioniert tatsächlich:</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>Ich habe einige der gängigen Beispiele aus der Elasticsearch Ruby-Client-Dokumentation getestet, und sie funktionieren wie erwartet:</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>Migration einer Ruby-Anwendung zu Elasticsearch</h2><p>Der erste Schritt besteht darin, <code>elasticsearch-ruby</code> in die Gemfile einzufügen. Nach dem Ausführen von <code>bundle install</code> wird das Elasticsearch Ruby Client Gem installiert. Wenn Sie Ihren Code vor der vollständigen Migration testen möchten, können Sie das <code>opensearch-ruby</code> Gem zunächst dort belassen.</p><p>Der nächste wichtige Schritt wird die Client-Instanziierung sein. Das hängt davon ab, wie Sie Elasticsearch betreiben. Um bei diesen Beispielen eine ähnliche Vorgehensweise beizubehalten, folge ich den Schritten unter <a href="https://www.elastic.co/downloads/elasticsearch">Elasticsearch herunterladen</a> und lokal ausführen.</p><p>Beim Ausführen von <code>bin/elasticsearch</code> startet Elasticsearch mit automatisch konfigurierten Sicherheitsfunktionen. Stellen Sie sicher, dass Sie das Passwort für den Elastic-Benutzer kopieren (Sie können es aber durch Ausführen <code>bin/elasticsearch-reset-password -u elastic</code> zurücksetzen). Wenn Sie diesem Beispiel folgen, stellen Sie sicher, dass Sie OpenSearch beenden, bevor Sie Elasticsearch starten, da beide auf demselben Port laufen.</p><p>Am Anfang von <code>example_code.rb</code> habe ich die OpenSearch-Client-Instanziierung auskommentiert und die Instanziierung für einen Elasticsearch-Client hinzugefügt:</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>Wie Sie sehen können, ist der Code in diesem Testszenario nahezu identisch. Dies hängt von der Art der Elasticsearch-Implementierung und der gewählten Verbindungs- und Authentifizierungsmethode ab. Dasselbe gilt hier wie bei OpenSearch in Bezug auf die Sicherheit: Die Option, SSL nicht zu überprüfen, dient nur zu Testzwecken und sollte nicht in der Produktion verwendet werden.</p><p>Sobald der Client eingerichtet ist, führe ich den Code erneut aus mit: <code>bundle exec ruby example_code.rb</code>. Und alles funktioniert einfach!</p><h2>Behebung von Migrationsproblemen</h2><p>Je nachdem, welche APIs Ihre Anwendung verwendet, besteht die Möglichkeit, dass Sie beim Ausführen Ihres Codes gegen Elasticsearch einen Fehler erhalten, wenn die APIs von OpenSearch voneinander abweichen. Die <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html">Dokumentation der REST-APIs</a> ist eine unverzichtbare Referenz für detaillierte Informationen zur Verwendung der APIs. Bitte prüfen Sie die Dokumentation für die Version von Elasticsearch, die Sie verwenden. Sie können auch auf die Referenz <a href="https://rubydoc.info/gems/elasticsearch-api"><code>Elasticsearch::API</code></a> verweisen.</p><p>Mögliche Fehler bei Elasticsearch sind beispielsweise:</p><ul><li><p><code>ArgumentError: Required argument '&lt;ARGUMENT&gt;' missing</code> - Dies ist ein Clientfehler, der auftritt, wenn einer Anfrage ein erforderlicher Parameter fehlt.</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> Dieser Fehler stammt von Elasticsearch und bedeutet, dass der Client-Code einen Parameter verwendet, den Elasticsearch für die verwendete API nicht erkennt.</p></li></ul><p>Der Elasticsearch-Client wird Fehler von Elasticsearch mit der detaillierten Fehlermeldung, die vom Server gesendet wird, melden. Selbst bei nicht unterstützten Parametern oder Endpunkten sollte die Fehlermeldung darüber informieren, was anders ist.</p><h2>Fazit</h2><p>Wie wir anhand dieses Beispielcodes gezeigt haben, ist die Migration einer Ruby-Anwendung von OpenSearch zu Elasticsearch von der Ruby-Seite her nicht allzu komplex. Sie müssen sich über die Versionsverwaltung und mögliche Unterschiede in den APIs der Suchmaschinen im Klaren sein. Bei den häufigsten Aktionen besteht die größte Änderung bei der Migration von Clients jedoch in der Instanziierung. In dieser Hinsicht ähneln sie sich beide, aber die Art und Weise, wie Host und Anmeldeinformationen definiert werden, variiert je nachdem, wie der Stack bereitgestellt wird. Sobald der Client eingerichtet ist und Sie überprüft haben, dass er eine Verbindung zu Elasticsearch herstellt, können Sie den OpenSearch-Client nahtlos durch den Elasticsearch-Client ersetzen.
</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>