Spark ElasticSearch Hadoop 更新とアップサートの例と説明

Spark ElasticSearch Hadoop 更新とアップサートの例と説明

  • オーケストレーション
5分で読めます 更新日 Oct 25, 2018

ポイント: このガイドでは、Apache Sparkを使用してPythonでElasticSearchドキュメントを更新する方法を詳述しています。簡単な例と必要な前提条件を提供し、Python用のElasticsearch-Hadoopコネクタの使用を強調しています。ガイドには、GitHubで利用可能なコードスニペットが含まれており、ドキュメントIDの取得や更新操作などの重要な概念を説明しています。

  • ElasticSearchドキュメントを更新するための例コードがGitHubで利用可能です。
  • 前提条件にはElasticSearch、Apache Spark、Hadoop-ElasticSearch jarファイルが含まれます。

ここでは、Apache Spark DataframeおよびRDDからElasticSearchドキュメントを更新するためのPythonコードを書く方法を説明します。

インターネット上にはいくつかの指示があります。ElasticSearchによって書かれたものは理解が難しく、例も提供されていません。ここでは、できるだけシンプルな例を作成します。

このコードは、ElasticSearch(ES)JSONドキュメントに追加のフィールドを追加します。つまり、ドキュメントを更新します。SparkはScalaとJavaのためのネイティブサポートを提供しています。しかし、Pythonの場合はElasticSearchによって書かれたElasticsearch-Hadoopコネクタを使用する必要があります。それにより、この操作はより複雑になります。

GitHubのコード

この演習のコードはここにあります:

ElasticSearchを更新

spark-submitでコードを実行

データを作成

前提条件

  • ES。バイナリをダウンロードし、apt-get installを使用しないでください。そこに保存されているバージョンは非常に古いです。
  • Apache Spark。
  • Hadoop-ElasticSearch jarファイル。ここからダウンロードすると、さまざまな言語用のjarsが提供されます。

データを追加

最初に、ESに2つのデータレコードを追加する必要があります。キーは表記です:school/doc/1

これは、インデックスschoolに、タイプdoc、ID1を追加することを意味します。

    curl -XPUT --header 'Content-Type: application/json' http://localhost:9200/school/doc/1 -d '{
   "school" : "Clemson"                 
}'

curl -XPUT --header 'Content-Type: application/json' http://localhost:9200/schools/doc/2 -d '{
   "school" : "Harvard"			
}'

以下のPythonコードをspark-submitジョブとして実行するためのコードです。pysparkでコードを1行ずつステップ実行するためには必要ありません。

    #!/bin/bash

NUM_CORES=*
DRIVER_MEM=3g

JARS="/usr/share/spark/spark-2.3.2-bin-hadoop2.7/jars/elasticsearch-hadoop-6.4.2/dist"

export SPARK_HOME="/usr/share/spark/spark-2.3.2-bin-hadoop2.7"
export PATH=$PATH:$SPARK_HOME/bin
export CODEPATH="/home/ubuntu/Documents/esearch"

cd $CODEPATH

$SPARK_HOME/bin/spark-submit --master local[$NUM_CORES] --driver-memory
$DRIVER_MEM --jars $JARS/elasticsearch-hadoop-6.4.2.jar
$CODEPATH/updateData.py

コードの説明

read.formatはESへの接続を開きます。重要な点は"es.read.metadata", "true"です。メタデータが必要です。これにより、更新操作に必要なドキュメントの_idが提供されます。

    reader = spark.read.format("org.elasticsearch.spark.sql").option("es.read.metadata", "true").option("es.nodes.wan.only","true").option("es.port","9200").option("es.net.ssl","false").option("es.nodes", "http://localhost")

次に、インデックスschool内のすべてのドキュメントを読み取ります。

    df = reader.load("school")
df.show()

次に、Harvardと等しい1つのレコードを見つけるためにフィルタリングします。

    df.filter(df["school"] == "Harvard").show()

今やdf.filter()操作はその場で動作します。つまり、新しいデータフレームを返さずに、現在のデータフレーム上で操作します。以下のように、フィルタ操作の後にHarvardのみが表示されます。

    df.show()
+---------+-------+--------------------+
|  school|           _metadata|
+---------+-------+--------------------+
| Harvard|[_index -> school...|
| Clemson|[_index -> school...|
+---------+-------+--------------------+

df.filter(df["school"] == "Harvard").show()
+---------+-------+--------------------+
|   school|           _metadata|
+---------+-------+--------------------+
| Harvard|[_index -> school...|
+---------+-------+--------------------+

メタデータから_idを取得する必要があります。これはマップです。したがって、これをRDDに変換し、collect()メソッドを使用してRowオブジェクトを作成します。次に、最初の行、2番目の列をインデックスで読み取り、名前で_idを取得します。その後、df.withColumnとlitを使用して、その値をデータフレームdf内の定数値として新しい列として書き込みます。

注意: データフレームには1行のみがあります。もしそれがもっとあれば、以下のコード全体でマップ操作を実行して、データフレーム内のすべてのレコードを更新する必要があります。

    r=df.rdd.collect()
id = r[0][1]['_id']
df2=df.withColumn("_id", lit(id))

次に、辞書としてesconfオブジェクトを作成します。インターネット上のコード例では、これをJSONとして見ることができます。しかし、以下の表記はよりクリーンで作業しやすいです。

注目すべき重要な項目は:

es.update.script.inline ctx._source.locationはlocationというフィールドを更新または作成することを意味します。ctx_sourceはそれを行うためのESオブジェクトです。
es.update.script.params location:は、インラインスクリプトes.update.script.inlineに渡されるパラメータ値です。<>はリテラルを書くことを意味します。フィールド値を書く場合は、これを省略します。
es.mapping.id これはESに対してデータフレームのid列を見て、それをドキュメントID_idとして使用するように指示します。ESはそれを使用して、ESで更新したいドキュメントを見つけます。
es.write.operation upsertは、文書が存在しない場合は追加し、そうでなければ更新することを意味します。updateはそれを更新することを意味します。
    esconf={}
esconf["es.mapping.id"] = "_id"
esconf["es.nodes"] = "localhost"
esconf["es.port"] = "9200"
esconf["es.update.script.inline"] = "ctx._source.location = params.location"
esconf["es.update.script.params"] = "location:"
esconf["es.write.operation"] = "upsert"

これによりデータが書き込まれます。**esconfは辞書escconfを読み取ることを意味します。mode("append")は、既存のドキュメントにフィールドを追加することを意味します。

    df2.write.format("org.elasticsearch.spark.sql").options(**esconf).mode("append").save("school/info")

今、ドキュメントをルックアップして、locationフィールドがCambridgeに更新されたことに気付きます。アイビーリーグのスノッブの群れ。

    curl -X GET 'http://localhost:9chool/info/_search'

{"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"school","_type":"info","_id":"2","_score":1.0,"_source":{"school":"Harvard","location":"Cambridge"}}]}}

完全なコード

    from pyspark import SparkContext, SparkConf
from pyspark.sql import SQLContext
from pyspark.sql.functions import lit

conf = SparkConf().setAppName("updateSchools")
sc = SparkContext(conf=conf)
sc.setLogLevel("INFO")
spark = SQLContext(sc)

reader = spark.read.format("org.elasticsearch.spark.sql").option("es.read.metadata", "true").option("es.nodes.wan.only","true").option("es.port","9200").option("es.net.ssl","false").option("es.nodes", "http://localhost")

df = reader.load("school")
df.show()

df.filter(df["school"] == "Harvard").show()

r=df.rdd.collect()
id = r[0][1]['_id']

df2=df.withColumn("_id", lit(id)) 

esconf={}
esconf["es.mapping.id"] = "_id"
esconf["es.nodes"] = "localhost"
esconf["es.port"] = "9200"
esconf["es.update.script.inline"] = "ctx._source.location = params.location"
esconf["es.update.script.params"] = "location:"
esconf["es.write.operation"] = "upsert"

df2.write.format("org.elasticsearch.spark.sql").options(**esconf).mode("append").save("school/info")

これらの投稿は私自身の意見であり、必ずしもBMCの立場、戦略、または意見を表しているわけではありません。

オーケストレーションの関連記事

The Briefを購読する

このオファーに登録することで、あなたはBMCのプライバシーポリシーを読み、同意したことを確認します。

ありがとう

あなたはThe Briefに登録されました
The Briefはメインフレームとエンタープライズオーケストレーション—BMC AMIとControl-M—および、両者に関するアナリストの研究、顧客の展開、イベントをカバーしています。