用Presto引擎访问watsonx.data,将其集成到MongoDB中来尝试
watsonx.data是基于开放式数据湖架构构建的,可以在低成本的对象存储上创建表,集成其他数据库,并利用这些数据库的数据通过开源的Presto引擎跨数据库进行SQL查询访问。
我在这篇文章中研究了如何使用SQL语句来获取JSON数据,虽然MongoDB也可以用来管理JSON数据。
由于问题的出现,我决定在本地安装开源的Presto,并将MongoDB集成进去进行确认。
这篇文章的内容 (Zhè de
以下の環境を作って試した
IBM Cloud Pak for Data(CP4D)上にwatsonx.dataを導入
CP4D バージョン: 4.7.3
watsonx.data (SW版) バージョン: 1.0.3
Databases for MongoDB (SaaS) バージョン: 5.0
IBM CloudのSaaSのサービスでMongoDBを作成してwatsonx.dataに組み込んでみたら問題が発生した。チケットをあげて確認したらwatsonx.dataの既知の問題とのこと。問題はそのうちに直ると思うので、とりあえず今回はオープンソースのPrestoを構築し、MongoDBのJSONデータがどのようにアクセスできるか確認してみた。
Pythonのプログラムでアクセスしてみたところ、JSONデータは階層化された配列で受信できることがわかった。さらに、データタイプを変えるとJSON形式の文字列で取得できることもわかった。
watsonx.dataでは複数のデータソースのデータをSQL文で結合して取得できるので、既知の問題が直れば、watsonx.dataにMongoDBを組み込んで、MongoDBのデータと他のデータソースのデータとを結合して利用することができる。
流程的步骤
创建MongoDB服务,并尝试使用MongoDB Compass进行连接确认。
尝试将创建的MongoDB嵌入watsonx.data。
搭建开源的Presto并将MongoDB嵌入。
使用Python访问Presto,并获取MongoDB的数据。
1. MongoDBサービスを作成し、MongoDB Compassで接続確認してみる
IBM Cloud Pak for Data(CP4D)上にwatsonx.dataを導入
CP4D バージョン: 4.7.3
watsonx.data (SW版) バージョン: 1.0.3
Databases for MongoDB (SaaS) バージョン: 5.0
IBM CloudのSaaSのサービスでMongoDBを作成してwatsonx.dataに組み込んでみたら問題が発生した。チケットをあげて確認したらwatsonx.dataの既知の問題とのこと。問題はそのうちに直ると思うので、とりあえず今回はオープンソースのPrestoを構築し、MongoDBのJSONデータがどのようにアクセスできるか確認してみた。
Pythonのプログラムでアクセスしてみたところ、JSONデータは階層化された配列で受信できることがわかった。さらに、データタイプを変えるとJSON形式の文字列で取得できることもわかった。
watsonx.dataでは複数のデータソースのデータをSQL文で結合して取得できるので、既知の問題が直れば、watsonx.dataにMongoDBを組み込んで、MongoDBのデータと他のデータソースのデータとを結合して利用することができる。
- 创建MongoDB服务,并尝试使用MongoDB Compass进行连接确认。
尝试将创建的MongoDB嵌入watsonx.data。
搭建开源的Presto并将MongoDB嵌入。
使用Python访问Presto,并获取MongoDB的数据。
1. MongoDBサービスを作成し、MongoDB Compassで接続確認してみる
MongoDBサービスの作成は、IBM CloudのカタログからDatabases for MongoDBを作成した。

しばらくすると利用可能となり、ステータスがアクティブとなる。次にMongoDBに接続するための認証情報を作成する。左側のメニューからService credentialsを選択し、右にあるNew credentialボタンをクリックして認証情報を作成する。

在MongoDB Compass中使用以下部分的连接信息:(.connection.mongodb.composed)
mongodb://ibm_cloud_36f4a076_6f69_4816_8036_13a190b7d741:a26f38ff9979d543b3fdff77212ae3caa8d3b69f18d6edaeaada1a1fb4ca7dfd@3d67c382-7065-45ad-84a9-19761d923525-0.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254,3d67c382-7065-45ad-84a9-19761d923525-1.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254,3d67c382-7065-45ad-84a9-19761d923525-2.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254/ibmclouddb?authSource=admin&replicaSet=replset&tls=true
书写格式如下。
mongodb://userid:password@
host1:port,host2:port,host3:port/ibmclouddb?
authSource=admin&replicaSet=replset&tls=true
还有,使用自签名证书进行TLS/SSL身份验证,也需要获取它。可以从上述途径获取,但是选择左侧菜单的”概述”,向下滚动即可显示以下画面。点击正中间的”下载证书”按钮进行下载。将其命名为mongodb1_tls.crt。

自分のPCにMongoDB Compassを導入した。起動すると以下のようなNew Connection画面が表示されるので、URIに上記で認証情報から抜き出した情報を貼り付け、さらに、Advanced Connection Optionsを展開し、TLS/SSLタブにあるSelect a file…ボタンをクリックして、ダウンロードしたmongodb1_tls.crtを登録する。

あとは画面下にあるSave & Connectボタンをクリックすると、設定情報を保存し(保存する名前を聞かれたのでibmcloud_mongodbとした)、MongoDBに接続する。
接続すると以下の画面が表示される。Databasesの右にある+をクリックし、今回のテストのために、データベース名test、コレクション名shopinfoを作成した。

以下のJSONデータをテスト用に作成したので、これをインポートする。
$ cat shop.json
{
"id": "1",
"name": "カフェA",
"info": {
"open": "8:00-21:00",
"mail": {
"info": "cafe-info@a.cafe.com",
"reservation": "reservation@a.cafe.com"
}
},
"review": [
{ "date": "2023-11-01", "comment": "おいしかった" },
{ "date": "2023-11-05", "comment": "落ち着いた雰囲気で良かった" }
]
}
{
"id": "2",
"name": "カフェB",
"info": {
"open": "7:00-20:00",
"mail": {
"info": "cafe-info@b.cafe.com",
"reservation": "reservation@b.cafe.com"
}
},
"review": [
{ "date": "2023-11-02", "comment": "メニューの種類が豊富で良かった" },
{ "date": "2023-11-03", "comment": "値段もリーズナブルだった" }
]
}
画面下部にあるImport Dataボタンをクリックし、上記のファイルを指定する。

结果如下,将导入两个记录。

尝试将已创建的MongoDB集成到watsonx.data中。
为了将MongoDB集成到watsonx.data中,展开watsonx.data基础设施管理器界面右侧的组件添加选项,并选择添加数据库。

以下のようなデータベースの追加画面が表示される。データベース・タイプとしてMongoDBを選択し、各種入力項目をセットする。

その後、設定したMongoDBをPrestoエンジンに組み込むことで、PrestoエンジンからMongoDBにアクセスできるようになることになっているが、残念ながら既知の問題によりアクセスできない。問題はMongoDBの自己証明書の処理に関するもので、以下のエラーが発生する。
unable to find valid certification path to requested target
因此,由于问题应该最终会得到解决,我构建了一个集成了MongoDB的开源Presto,并测试了如何通过Presto的SQL访问MongoDB的JSON数据。
尝试构建集成MongoDB的开源Presto。
Presto的构建请参考以下URL(安装版本为0.283)。
-
Deploying Presto
MongoDB Connector
MongoDB的自签名证书需要嵌入到JKS(Java KeyStore)中。因此,可以使用以下命令创建JKS文件并将MongoDB的自签名证书添加进去。
(假设MongoDB的自签名证书别名为mongodb1,JKS的密码为Passw0rd)
keytool -import -trustcacerts -alias mongodb1 -file mongodb1_tls.crt -keystore presto.jks -storepass Passw0rd
这个信息应在/etc/jvm.config文件中按以下方式指定(最后两行)。
-server
-Xmx16G
-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+UseGCOverheadLimit
-XX:+ExplicitGCInvokesConcurrent
-XX:+HeapDumpOnOutOfMemoryError
-XX:+ExitOnOutOfMemoryError
-Djavax.net.ssl.trustStore=/xxx/presto-server-0.283/etc/presto.jks
-Djavax.net.ssl.trustStorePassword=Passw0rd
Presto可以由多个工作节点组成,但在这里,我们选择在一个进程中同时运行协调器和工作节点。配置文件是etc/config.properties文件,在这里,我们还要注册JSK的信息。
coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery-server.enabled=true
discovery.uri=http://localhost:8080
http-server.https.keystore.path=/xxx/presto-server-0.283/etc/presto.jks
http-server.https.keystore.key=Passw0rd
MongoDB的嵌入是在etc/catalog/mongodb.properties文件中指定如下。
connector.name=mongodb
mongodb.seeds=3d67c382-7065-45ad-84a9-19761d923525-0.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254,3d67c382-7065-45ad-84a9-19761d923525-1.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254,3d67c382-7065-45ad-84a9-19761d923525-2.bqfh4fpt0vhjh7rs4ot0.databases.appdomain.cloud:32254
mongodb.credentials=ibm_cloud_36f4a076_6f69_4816_8036_13a190b7d741:a26f38ff9979d543b3fdff77212ae3caa8d3b69f18d6edaeaada1a1fb4ca7dfd@admin
mongodb.ssl.enabled=true
mongodb.socket-keep-alive=true
mongodb.socket-timeout=30000
mongodb.required-replica-set=replset
主要内容包括在`mongodb.seeds`指定连接主机名和端口号的列表,以及在`mongodb.credentials`中除了用户名和密码之外,还指定`authSource`为admin(用于保存认证信息的集合名称)。
此外,Java版本为OpenJDK build 21.0.1时出现以下错误。
Unable to load cache item
更换为Java版本”1.8.0_391″后,程序正常运行。
尝试使用Python访问Presto并获取MongoDB数据。
为了在Python中访问Presto,我们安装了presto-python-client包并导入prestodb来使用。
安装Presto Python客户端的软件包
pip install presto-python-client
访问内置MongoDB的Presto程序
import prestodb
if __name__ == '__main__':
conn = prestodb.dbapi.connect(
host='localhost',
port=8080,
user='admin',
http_scheme='http',
# auth=prestodb.auth.BasicAuthentication('admin','xxx')
)
# conn._http_session.verify = '/certs/xxx.crt'
cur = conn.cursor()
cur.arraysize = 100 # 100がデフォルト
cur.execute('select * from mongodb.test.shopinfo')
while True:
rows = cur.fetchmany()
if len(rows) == 0:
break
for row in rows:
print(row)
cur.close()
conn.close()
実行すると以下の結果が得られた。
$ python presto_access_mongodb.py
['1', 'カフェA', ['8:00-21:00', ['cafe-info@a.cafe.com', 'reservation@a.cafe.com']], [['2023-11-01', 'おいしかった'], ['2023-11-05', '落ち着いた雰囲気で良かった']]]
['2', 'カフェB', ['7:00-20:00', ['cafe-info@b.cafe.com', 'reservation@b.cafe.com']], [['2023-11-02', 'メニューの種類が豊富で良かった'], ['2023-11-03', '値段もリーズナブルだった']]]
各行で列の値が配列でセットされ、JSONの階層構造は配列を階層化してデータを保持していることがわかる。例えば、3番目の列は”info”キーの値を保持する。最初の行(レコード)の3番目のデータは、MongoDBでは以下のように保持されている。
"info": {
"open": "8:00-21:00",
"mail": {
"info": "cafe-info@a.cafe.com",
"reservation": "reservation@a.cafe.com"
}
}
パースして特定の情報を表示させるためには配列の要素数を指定すればよく、上記の3番目の列の値をパースするために、上記のプログラムの下記の部分を
for row in rows:
print(row)
请尝试将以下内容以中文进行更改。
for row in rows:
# print(row)
print(f'オープン: {row[2][0]}')
print(f'mail(情報): {row[2][1][0]}')
print(f'mail(予約): {row[2][1][1]}')
然后可以得出以下结果。
$ python presto_access_mongodb.py
オープン: 8:00-21:00
mail(情報): cafe-info@a.cafe.com
mail(予約): reservation@a.cafe.com
オープン: 7:00-20:00
mail(情報): cafe-info@b.cafe.com
mail(予約): reservation@b.cafe.com
如果你想将MongoDB中以JSON格式存储的数据处理为JSON数据,你可以通过更改列的数据类型来接收JSON格式的字符串,从而在Python中将其作为JSON处理。通过使用Presto CLI来确认数据类型,可以得到以下结果。
$ ./presto --server localhost:8080
presto> describe mongodb.test.shopinfo;
Column | Type | Extra | Comment
--------+------------------------------------------------------------------------+-------+---------
id | varchar | |
name | varchar | |
info | row("open" varchar, "mail" row("info" varchar, "reservation" varchar)) | |
review | array(row("date" varchar, "comment" varchar)) | |
(4 rows)
MongoDBのデータタイプは、最初にPrestoからMongoDBの該当コレクションにアクセスするとPrestoが自動生成し、そのコレクションが属すDBの_schemaコレクションにデータタイプを保存することがわかった。_schemaコレクションには以下のような情報が保存されている。



尝试将Python程序重置为初始状态并运行。
$ python presto_access_mongodb.py
['1', 'カフェA', '{ "open" : "8:00-21:00", "mail" : { "info" : "cafe-info@a.cafe.com", "reservation" : "reservation@a.cafe.com" } }', '[{ "date" : "2023-11-01", "comment" : "おいしかった" }, { "date" : "2023-11-05", "comment" : "落ち着いた雰囲気で良かった" }]']
['2', 'カフェB', '{ "open" : "7:00-20:00", "mail" : { "info" : "cafe-info@b.cafe.com", "reservation" : "reservation@b.cafe.com" } }', '[{ "date" : "2023-11-02", "comment" : "メニュ\\u30fcの種類が豊富で良かった" }, { "date" : "2023-11-03", "comment" : "値段もリ\\u30fcズナブルだった" }]']
3番目の列と4番目の列がJSON形式に変わったことがわかる。上記の3番目の列の値をパースするために、上記のプログラムの下記の部分を
for row in rows:
print(row)
# print(f'オープン: {row[2][0]}')
# print(f'mail(情報): {row[2][1][0]}')
# print(f'mail(予約): {row[2][1][1]}')
请尝试将以下内容用中文重新表达。
for row in rows:
# print(row)
# print(f'オープン: {row[2][0]}')
# print(f'mail(情報): {row[2][1][0]}')
# print(f'mail(予約): {row[2][1][1]}')
jinfo = json.loads(row[2])
print(f'オープン: {jinfo["open"]}')
print(f'mail(情報): {jinfo["mail"]["info"]}')
print(f'mail(予約): {jinfo["mail"]["reservation"]}')
此外,还要添加 import json。
import prestodb
import json
if __name__ == '__main__':
...
执行后会得到以下结果。
$ python presto_access_mongodb.py
オープン: 8:00-21:00
mail(情報): cafe-info@a.cafe.com
mail(予約): reservation@a.cafe.com
オープン: 7:00-20:00
mail(情報): cafe-info@b.cafe.com
mail(予約): reservation@b.cafe.com
就Python来说,有以上两个选择,但对于Java来说,由于处理JSON数据很困难,所以我认为最好的方式是使用层级化的数组来处理。