Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
NaotoSakai
Advisor
Advisor
0 Kudos

はじめに


今回は忘備録的なブログとなります。

とあるSAP Cloud Platform上のアプリを開発していて、クライアント側にあるExcelファイルのデータをSAP HANA Cloud上のテーブルにインポートしたいという要件が発生しました。

以前Maxime Simonが解説したようにSAP HANA Cloudへデータをインポートするには様々な方法があります。しかしながら今回の場合、「作業を行うのは事務員の方」ということもあり、簡単かつローコストな方法が求められました。
・SAP Database Explorer/DBeaver
これらのインポート機能を開発者ではない一般の方に使用させるのは難しいと判断しました。
・SAP HANA Smart Data Integration
DP Agentを事務員方のPCにインストールしてセットアップするのはちょっと気が引けます。また、このことの為にサーバー的なマシンを用意するのもコストの面で気が引けます。

アプリはNode.jsで組まれたアプリで、もともとWebブラウザから画像をアップロードし、Object Storeに格納する機能があります。これと同じ様な方法であれば事務員の方でも問題なく実行できるはずです。

ということで私はデータファイルを一旦Object Storeに格納し、そこからSAP HANA Cloudへインポートするという方法を取ってみることにしました。このブログはその手法の解説です。言語はNode.jsを使用しています。








注意1:

本来の要件は上記本文にあるように「Excelファイルのインポート」でした。実際のアプリではモジュールを用いてExcelのシートをCSVファイルに変換したものをObject Storeに格納していますが、その部分は割愛しCSVファイルをアップロードし、それをインポートするということで解説させて頂きます。

注意2:

本ブログはSAP Cloud Platform Cloud foundry on AWSを対象としています。on Azureでも同様の方法が取れると思いますが確認はしていません。

はじめに行ってみたこと


当初私はこの要件をあまり難しく考えずに、単純に、アップロードされたCSVファイルを配列としてメモリへ格納し、SAP HANA CloudへInsert文で1行1行格納させるコードを記述しました。単純化したコードでいうと以下になります。
    const csvSync = require('csv-parse/lib/sync');
let csvdata = fs.readFileSync('/app/public/temp/' + req.file.filename);
let csvarray = csvSync(csvdata); //Convert csv file to array
..........

var sql = 'INSERT INTO "HCIMPORTSAMPLE_HDI_DB_1"."hcimportsample.db::testtable" VALUES(?,?,?,?,?,?,?,?,?,?);';
var stmt = conn.prepare(sql);
for (let i=0;i<csvarray.length;i++){
try {
stmt.exec([csvarray[i][0],csvarray[i][1],csvarray[i][2],csvarray[i][3],csvarray[i][4],csvarray[i][5],csvarray[i][6],csvarray[i][7],csvarray[i][8],csvarray[i][9]]);
} catch (err) {
console.log("Insert error --- ", i.toString());
console.log("SQL=", sql);
console.log("DB Error: SQL Execution --- ", err);
return;
}
}



*このコードはWebブラウザからアップロードしたCSVファイルを一旦/app/temp/public以下に保存しています。

結論からいうと、この処理はCSVファイル内の行数が数行レベルであれば問題ないでしょう。しかし、10000件のテストファイルでは40秒ほど実行に時間がかかりました。(ファイルアップロード含む)

このループ前に

conn.setAutoCommit(false);

を付けて、このループを1トランザクションとして実行した場合でもさほど劇的な改善はありませんでした。


これを良しとするかは要件次第です。ただ、ちょっと時間がかかり過ぎだなと思います。

なんとか出来ないかと思い、違う方法を検討します。SAP HANA CloudはS3やAzure Storageからのデータインポートが可能です。SAP Object Storeの実体はこれらですので、IMPORT文でSAP HANA Cloudへのインポートも可能です。そこで一旦CSVファイルをObject Storeにアップロードし、それからインポートするという手法を行ってみることにしました。

Object Storeへのアクセス設定


今回はObject StoreにてAWS S3を使用しています。Maxime Simonが解説した文章でのS3へのアクセスで必要な情報はObject StoreをアプリケーションにバインドするとSensitive Dataとして閲覧できます。


これらの情報を用いてHANA Cloudからアクセスできるように設定してください。また、今回はインポートを行いますので


HDIコンテナのSensitive Dataで確認できるuserにIMPORT権限を与えることを忘れないでください。

Object Storeからのインポート


Node.jsからObject Storeへのデータアップロードはaws-sdkを用いて行います。アプリケーションをバインドしていればvcap_servicesを用いることでコードへのアクセス情報の直接の記述は不要です。

S3へのファイルアップロードからHANA Cloudデータベースへのデータインポートを単純化したコードでは以下のようになります。
    var AWS = require('aws-sdk');
let csvdata = fs.readFileSync('/app/public/temp/' + req.file.filename);

const credentials = new AWS.Credentials({ accessKeyId: vcap_services.objectstore[0].credentials.access_key_id, secretAccessKey: vcap_services.objectstore[0].credentials.secret_access_key });
AWS.config.credentials = credentials;
AWS.config.update({ region: vcap_services.objectstore[0].credentials.region });

var s3 = new AWS.S3();
var params = {
Bucket: vcap_services.objectstore[0].credentials.bucket,
Key: req.file.filename
};

params.Body = csvdata;

var putObjectPromise = s3.putObject(params).promise();
putObjectPromise.then(function (data) {

var sql = "IMPORT FROM CSV FILE 's3-" + vcap_services.objectstore[0].credentials.region + "://" +
vcap_services.objectstore[0].credentials.access_key_id + ":" + vcap_services.objectstore[0].credentials.secret_access_key + "@" +
vcap_services.objectstore[0].credentials.bucket + "/" + req.file.filename + "' INTO " +
'"HCIMPORTSAMPLE_HDI_DB_1"."hcimportsample.db::testtable";';

var stmt = conn.prepare(sql);

try {
stmt.exec();
} catch (err) {
console.log("IMPORT ERROR --- ");
console.log("SQL=", sql);
console.log("DB Error: SQL Execution --- ", err);
}
return;
}).catch(function (err) {
console.log(err);
return;
});

この例の場合、先のループ挿入の例のコードを改造しましたのでCSVファイルはアプリケーションローカルのディレクトリに配置しそれをObject Storeにコピーしています。本来はデータを直接Object Storeにアップロードしたほうが良いでしょう。

そして、S3へアップロードしたファイルをHANA Cloudへインポートします。

この例の場合、先と同じデータをアップロードを含めて2秒以下でインポートができました。やはりIMPORTは高速です。

最後に


このようにアプリケーションの中でも使用可能で、特に速度については有用です。

記事中にはコードの一部しか貼り付けできませんでしたので、Webアプリケーションとして実行できる簡単なサンプルを用意しました。
こちらに公開しましたのでご興味のある方は試してみてください。


https://github.com/naotos-git/ImportfromObjStore