IDEA Note

  • M1 MacでDockerを使ってPowerShellを動作させる

    M1 MacでDockerを使ってPowerShellを動作させる

    M1 MacでDockerを使用してPowerShellを動作させる際には、いくつかの課題が生じる可能性があります。

    この記事では、DockerfileをM1 Macでビルドする際に遭遇する可能性がある問題とその解決策を説明します。

    問題の概要

    以下のDockerfileを使用してビルドを試みると、特定のエラーが発生する可能性があります。

    FROM --platform=linux/x86_64 mcr.microsoft.com/powershell:7.3-ubuntu-22.04
    RUN pwsh -Command Install-Module -Name Microsoft.Graph -Scope AllUsers -F

    エラーメッセージは以下の通りです。

    ---> [Warning] The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
    ---> Running in 28a633eea3df
    An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit.
    An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit.
    qemu: uncaught target signal 11 (Segmentation fault) - core dumped
    Segmentation fault
    The command '/bin/sh -c pwsh -Command Install-Module -Name Microsoft.Graph -Scope AllUsers -F' returned a non-zero code: 139

    このエラーは、使用しているイメージのプラットフォームがホストと一致しない場合に発生します。

    具体的には、このエラーはx86_64(AMD64)プラットフォーム向けのイメージをARM64プラットフォーム(M1 Macが使用しているプラットフォーム)で実行しようとしたときに発生します。

    さらに、Segmentation faultというエラーになることもあります。

    これは、プログラムが不正なメモリ領域にアクセスしようとしたときに発生します。

    このエラーは通常、プログラムのバグや、プログラムが不適切な方法でメモリを操作した結果として発生します。

    この場合、エラーはQEMU(異なるCPUアーキテクチャ間でのエミュレーションを提供するソフトウェア)から発生しており、x86_64プラットフォーム向けのコードをARM64プラットフォームで実行しようとしたことが原因と考えられます。

    解決策

    この問題を解決するためには、ARM64プラットフォーム向けのPowerShellを直接インストールする必要があります。

    https://github.com/GitSumito/CodeArsenal/blob/main/Powershell_On_Docker_For_M1Mac/Dockerfile

    上のリポジトリは build したDockerfile です。

    以下 Dockerfile の解説です。

    # Select the base image
    FROM arm64v8/ubuntu:latest

    この行では、ベースイメージとしてARM64プラットフォーム向けの最新のUbuntuイメージを選択しています。

    # Update the package lists for upgrades for security purposes
    RUN apt-get update && apt-get upgrade -y

    この行では、セキュリティのためにパッケージリストを更新し、アップグレードします。

    # Install necessary tools
    RUN apt-get install -y curl wget tar sudo
    # Install the ICU library
    RUN apt-get install -y libicu-dev

    この行では、ICU(International Components for Unicode)ライブラリをインストールしています。ICUは、Unicodeとグローバリゼーション(i18n)サポートを提供するC/C++およびJavaライブラリです。

    # Download the PowerShell binary
    RUN wget -O /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz

    この行では、PowerShellのバイナリをダウンロードしています。wgetコマンドを使用して、指定したURLからPowerShellのtar.gzファイルをダウンロードし、/tmpディレクトリにpowershell.tar.gzという名前で保存します。

    # Create the target folder where PowerShell will be placed
    RUN mkdir -p /usr/local/microsoft/powershell/7.3.4

    この行では、PowerShellが配置されるターゲットフォルダを作成します。

    # Expand PowerShell to the target folder
    RUN tar zxf /tmp/powershell.tar.gz -C /usr/local/microsoft/powershell/7.3.4

    この行では、ダウンロードしたPowerShellのtar.gzファイルをターゲットフォルダに展開します。

    # Set execute permissions
    RUN chmod +x /usr/local/microsoft/powershell/7.3.4/pwsh

    この行では、PowerShell実行ファイルに実行権限を設定します。

    # Create a symbolic link that points to pwsh
    RUN ln -s /usr/local/microsoft/powershell/7.3.4/pwsh /usr/local/bin/pwsh

    この行では、pwshへのシンボリックリンクを作成します。これにより、どのディレクトリからでもpwshコマンドを使用してPowerShellを起動できるようになります。

    # Install necessary PowerShell modules
    RUN pwsh -Command Install-Module -Name ExchangePowerShell -F
    RUN pwsh -Command Install-Module -Name Microsoft.Graph -F

    最後に、必要なPowerShellモジュールをインストールします。この例では、ExchangePowerShellモジュールとMicrosoft.Graphモジュールをインストールします。

    Dockerfileのビルドが成功すると、以下のような出力が表示されます:

    ---> c6bd065a23d8
    Step 6/11 : RUN mkdir -p /usr/local/microsoft/powershell/7.3.4
    ---> Running in 77c3cfaf924e
    Removing intermediate container 77c3cfaf924e
    ---> 19263b7b1096
    Step 7/11 : RUN tar zxf /tmp/powershell.tar.gz -C /usr/local/microsoft/powershell/7.3.4
    ---> Running in 6f9b149944ae
    Removing intermediate container 6f9b149944ae
    ---> 86c0945e8a86
    Step 8/11 : RUN chmod +x /usr/local/microsoft/powershell/7.3.4/pwsh
    ---> Running in bed70b0443d1
    Removing intermediate container bed70b0443d1
    ---> b767beaee0b3
    Step 9/11 : RUN ln -s /usr/local/microsoft/powershell/7.3.4/pwsh /usr/local/bin/pwsh
    ---> Running in 26c1c7b4b1cf
    Removing intermediate container 26c1c7b4b1cf
    ---> ff72047deef1
    Step 10/11 : RUN pwsh -Command Install-Module -Name ExchangePowerShell -F
    ---> Running in e024612672c1
    Removing intermediate container e024612672c1
    ---> 08eb8f79bdd4
    Step 11/11 : RUN pwsh -Command Install-Module -Name Microsoft.Graph -F
    ---> Running in 2988a85004a6
    Removing intermediate container 2988a85004a6
    ---> 0205240f3f6f
    Successfully built 0205240f3f6f
    Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

    このDockerfileを使用することで、M1 MacでもDocker上でPowerShellを動作させることが可能になります。

  • SQLの再帰と組織階層の探索:WITH RECURSIVEとUNION ALLを理解する

    SQLの再帰と組織階層の探索:WITH RECURSIVEとUNION ALLを理解する

    組織のデータを扱う際、階層構造を理解し、それをデータベースで表現することがよくあります。

    しかし、階層的なデータの探索は一見複雑に見えることがあります。今日は、その一つの解決策としてSQLの再帰クエリを使った方法を解説します。

     

    create or replace TABLE Organization (
    Org_Code VARCHAR(11) NOT NULL,
    Org_Name VARCHAR(400),
    Parent_Org_Code VARCHAR(11),
    Layer_Number NUMBER(2),
    constraint Org_PK primary key (Org_Code)
    );

    データは以下の通り入っているものとします。

    Org_Code Org_Name Parent_Org_Code Layer_Number
    ORG-001 Org A ORG-001 1
    ORG-002 Org B ORG-001 2
    ORG-003 Org C ORG-001 2
    ORG-004 Org D ORG-002 3
    ORG-005 Org E ORG-002 3
    ORG-006 Org F ORG-003 3
    ORG-007 Org G ORG-004 4
    ORG-008 Org H ORG-004 4
    ORG-009 Org I ORG-005 4
    ORG-010 Org J ORG-006 4

    このテーブルは、組織コード Org_Code、組織の名称 Org_Name、親組織のコード Parent_Org_Code、およびその組織が階層の何層目に位置するか Layer_Number を格納しています。

    組織の階層を表示したい場合、親組織から子組織までのパスを表現するために、SQLの再帰クエリを使用します。

    再帰クエリは、自身を呼び出すクエリであり、これにより階層データのような複雑な構造を効果的に解析できます。

    以下のクエリでは、WITH RECURSIVE 句を使用して、階層構造を再帰的に探索します:

    WITH RECURSIVE org_path AS (
    SELECT
    Org_Code,
    Org_Name,
    Parent_Org_Code,
    CAST(Org_Code AS VARCHAR(500)) AS Org_Path,
    Layer_Number,
    Org_Name AS Layer_Name,
    Layer_Number AS Layer_Num
    FROM
    Organization
    WHERE
    Org_Code = Parent_Org_Code
    UNION ALL
    SELECT
    o.Org_Code,
    o.Org_Name,
    o.Parent_Org_Code,
    CONCAT(r.Org_Path, ' -> ', o.Org_Code),
    o.Layer_Number,
    CONCAT(r.Layer_Name, ' -> ', o.Org_Name),
    o.Layer_Number
    FROM
    Organization o
    JOIN
    org_path r
    ON
    o.Parent_Org_Code = r.Org_Code
    WHERE
    o.Org_Code <> o.Parent_Org_Code
    )
    SELECT * FROM org_path;

    この再帰クエリは2部構成で、最初の部分(ベースケース)では自身が親組織である組織(つまり最上位の組織)を選択しています。ここでは、Org_CodeとParent_Org_Codeが同じ行を選択します。これが再帰の開始点となります。

    次にUNION ALLでベースケースと再帰ケースを結合します。再帰ケースでは、再帰CTE org_path を再帰的に結合して、親組織から次の子組織へと移動します。この部分ではParent_Org_Code が先ほど選択した行のOrg_Code と一致する行を選択します。

    この操作を行うことで、親組織から子組織、孫組織、さらにその下の組織へとパスをたどることができます。

    そして最終的にSELECT * FROM org_pathで再帰CTEからすべての行を選択します。

    これにより、親組織から各組織へのパスを含む結果セットが得られます。

    Org_Code Org_Name Parent_Org_Code Org_Path Layer_Number Layer_Name Layer_Num
    ORG-001 Org A ORG-001 ORG-001 1 (1) Org A 1
    ORG-002 Org B ORG-001 ORG-001 -> ORG-002 2 (1) Org A -> (2) Org B 2
    ORG-003 Org C ORG-001 ORG-001 -> ORG-003 2 (1) Org A -> (2) Org C 2
    ORG-004 Org D ORG-002 ORG-001 -> ORG-002 -> ORG-004 3 (1) Org A -> (2) Org B -> (3) Org D 3
    ORG-005 Org E ORG-002 ORG-001 -> ORG-002 -> ORG-005 3 (1) Org A -> (2) Org B -> (3) Org E 3
    ORG-006 Org F ORG-003 ORG-001 -> ORG-003 -> ORG-006 3 (1) Org A -> (2) Org C -> (3) Org F 3
    ORG-007 Org G ORG-004 ORG-001 -> ORG-002 -> ORG-004 -> ORG-007 4 (1) Org A -> (2) Org B -> (3) Org D -> (4) Org G 4
    ORG-008 Org H ORG-004 ORG-001 -> ORG-002 -> ORG-004 -> ORG-008 4 (1) Org A -> (2) Org B -> (3) Org D -> (4) Org H 4
    ORG-009 Org I ORG-005 ORG-001 -> ORG-002 -> ORG-005 -> ORG-009 4 (1) Org A -> (2) Org B -> (3) Org E -> (4) Org I 4
    ORG-010 Org J ORG-006 ORG-001 -> ORG-003 -> ORG-006 -> ORG-010 4 (1) Org A -> (2) Org C -> (3) Org F -> (4) Org J 4

    以上がSQLの再帰クエリを使った組織の階層構造探索の基本的な考え方です。

     

    振る舞いについてもう少し踏み込む

    基本ケース

    基本ケースは、再帰が始まる地点を定義します。このクエリでは、基本ケースは自己参照(Org_Code = Parent_Org_Code)の組織を見つけます。これは通常、組織階層のルートを示します。

    SELECT
    Org_Code,
    Org_Name,
    Parent_Org_Code,
    CAST(Org_Code AS VARCHAR(500)) AS Org_Path,
    Layer_Number,
    Org_Name AS Layer_Name,
    Layer_Number AS Layer_Num
    FROM
    Organization
    WHERE
    Org_Code = Parent_Org_Code

    この部分のクエリを実行すると、以下の行が得られます。

    Org_Code Org_Name Parent_Org_Code Org_Path Layer_Number Layer_Name Layer_Num
    ORG-001 Org A ORG-001 ORG-001 1 Org A 1

    再帰ステップ

    再帰ステップは、基本ケースから始まり、その結果を用いて組織の子ノードを見つけます。このステップは、自己参照でないすべての組織(つまり、Org_Code <> Parent_Org_Code)を見つけます。

    SELECT
    o.Org_Code,
    o.Org_Name,
    o.Parent_Org_Code,
    CONCAT(r.Org_Path, ' -> ', o.Org_Code),
    o.Layer_Number,
    CONCAT(r.Layer_Name, ' -> ', o.Org_Name),
    o.Layer_Number
    FROM
    Organization o
    JOIN
    org_path r
    ON
    o.Parent_Org_Code = r.Org_Code
    WHERE
    o.Org_Code <> o.Parent_Org_Code

    この部分のクエリは、基本ケースから得られた結果(つまり、ORG-001)を用いて、その子ノード(ORG-002とORG-003)を見つけます。この結果は以下のようになります。

    Org_Code Org_Name Parent_Org_Code Org_Path Layer_Number Layer_Name Layer_Num
    ORG-002 Org B ORG-001 ORG-001 -> ORG-002 2 Org A -> Org B 2
    ORG-003 Org C ORG-001 ORG-001 -> ORG-003 2 Org A -> Org C 2

    このステップは、すべての組織が見つかるまで再帰的に繰り返されます。つまり、ORG-002とORG-003の子ノード(ORG-004, ORG-005, ORG-006)、その子ノード(ORG-007, ORG-008, ORG-009, ORG-010)を見つけます。

    最終的な結果は、基本ケースとすべての再帰ステップの結果を連結したものになります。これは、UNION ALLによって行われます。UNION ALLは、2つのSELECT文の結果を一つのテーブルに結合します。

    このクエリの結果は、組織の階層を表現するパスを生成します。各行は、特定の組織へのパス(Org_Path)、その組織の名前(Layer_Name)、およびその組織が階層の何層目に位置しているか(Layer_Num)を示します。

    以上が、このSQLクエリがどのように動作するかの詳細な説明です。各ステップで何が起こるかを理解することで、このクエリがどのように組織の階層を探索し、パスを生成するかを理解することができるはずです。

    このテクニックは、階層的なデータを持つ任意のシナリオに適用でき、特に組織構造やファイルシステム、ソーシャルネットワークの関係などで有用です。

     

  • Flaskにおける特定のルートのログ出力の無効化について: AWS EC2/ECS

    Flaskにおける特定のルートのログ出力の無効化について: AWS EC2/ECS

    FlaskはPythonで開発された軽量なWebフレームワークで、そのシンプルさと拡張性から多くの開発者に利用されています。

    今回は、特にAWSのEC2やECSでFlaskを使用している開発者の皆様向けに、ある一般的な問題とその解決策について共有させていただきます。

    サーバーのヘルスチェックは重要な部分であり、私たちはそのためのエンドポイント/healthzを定期的にポーリングしています。

    しかし、これがもたらすログ出力の多さが問題となり、重要な情報が見づらくなることがあります。

    そこで、ヘルスチェックのエンドポイントに関するログだけを無効にする方法について考察しました。

    解決策:特定のルートのログ出力をフィルタリングする

    この問題に対する答えの一つとして、PythonのloggingモジュールのFilterクラスを用いる方法があります。このクラスを継承し、カスタムフィルタクラスを作成します。このフィルタをロガーに追加することで、特定のログメッセージをフィルタリングできます。

    import logging

    class HealthCheckFilter(logging.Filter):
    def filter(self, record):
    return "/healthz" not in record.getMessage()

    ここで定義したHealthCheckFilterクラスは、ログメッセージに/healthzが含まれていない場合にのみTrueを返します。

    したがって、/healthzがメッセージに含まれるログエントリはフィルタリングされ、出力されません。

    そして、このフィルタを適用したいロガーに追加します:

    logger = Logger().getLogger('default')
    logger.addFilter(HealthCheckFilter())

    これにより、ヘルスチェックに関するログ出力が無効化され、ログの可読性が向上します。

    注意点

    この解決策は、特定のロガーに対してのみ適用されます。全体のロガーへの適用はされません。

    例えば、Flaskは内部的にWerkzeugサーバーを利用しており、そのサーバーは自己のロガー(‘werkzeug’)を持っています。

    そのため、もしWerkzeugサーバーからのログもフィルタリングしたい場合は、同様にフィルタを追加する必要があります。

    この記事がAWSのEC2やECSで大規模なFlaskアプリケーションを運用している皆様の一助になれば幸いです。

    特定のエンドポイントのログ出力を制御することで、ログの可読性が向上し、重要な情報へのアクセスが容易になります。

    私たちはまだ学び続けており、他の解決策や改善点があれば、ぜひ共有いただければと思います。

  • AWS CLIでエスケープなしのJSONを送信する

    AWS CLIでエスケープなしのJSONを送信する

    AWS CLIを使って作業を行うとき、しばしばJSON文字列を引数として渡す必要があります。しかし、これが難しい場合もあります。特に文字列内にエスケープが必要な文字(バックスラッシュなど)が含まれている場合です。

    今回は、エスケープなしのJSON文字列をAWS CLIに直接渡す方法を紹介します。

    ヒアドキュメントの使用

    ヒアドキュメント(Here Document)は、シェルスクリプトのリダイレクトの一種で、複数行のテキストを直接スクリプト内に記述するための方法です。

    ヒアドキュメント内部では、一部のエスケープシーケンスが解釈されずバックスラッシュがただの文字として扱われます。

    これを利用すると、バックスラッシュを含む文字列をエスケープせずに直接AWS CLIに渡すことが可能になります。

    具体的には、以下のようにします:

    aws sqs send-message --profile your-profile --queue-url "your-queue-url" --message-group-id "your-message-group-id" --message-body "$(cat <<EOF
    {
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
    }
    EOF
    )
    "

    ここで、

    $(cat <<EOF ... EOF)

    がヒアドキュメントの部分で、これが完全に展開された後で

    aws sqs send-message

    コマンドが実行されます。ヒアドキュメント内のJSON文字列はエスケープなしでそのまま扱われるため、特殊文字を含むパスでも問題なくAWS CLIに渡すことができます。

    まとめ

    AWS CLIでエスケープが必要な文字を含むJSONを扱う際には、ヒアドキュメントが非常に便利です。ヒアドキュメントを使うと、エスケープなしで文字列をそのまま扱うことができるので、コマンドラインでの作業が少し楽になります。

  • SSH ProxyJumpを利用した便利な接続方法

    SSH ProxyJumpを利用した便利な接続方法

    SSHを使用してサーバーに接続する際、中継サーバー(bastionホスト)を経由しなければならない場面は珍しくありません。こ

    の手順は煩わしく、特に同じ設定を繰り返し行う必要がある場合、非効率的に感じるかもしれません。

    そんな時に便利なのがSSHのプロキシジャンプ(ProxyJump)機能です。一度のコマンドで中継サーバーを経由してターゲットサーバーに接続することが可能になります。

    設定は以下のように行います。

    まずは、~/.ssh/configに中継サーバーとターゲットサーバーの設定を記述します。

    Host stg-bastion
    Hostname xxxxxxxx
    IdentityFile ~/.ssh/your_identity_file

    Host target-server
    Hostname xxxxxxxx
    IdentityFile ~/.ssh/your_identity_file
    ProxyJump stg-bastion

    ここでは、stg-bastionという名前の中継サーバーに接続し、そこを経由してtarget-serverという名前のターゲットサーバーに接続します。どちらの接続でも同じIdentityFileが使用されます。

    設定を追加したら、以下のコマンドを実行することで、直接target-serverサーバに接続できます:

    ssh target-server

    この機能を使用することで、SSH接続の作業を大幅に効率化できます。あなたもぜひ試してみてください。

    以上、SSH ProxyJumpを利用した便利な接続方法についての記事でした。参考になれば幸いです。

  • jqコマンドでJSONから指定した項目を取得・変換する

    jqコマンドでJSONから指定した項目を取得・変換する

    JSONはウェブのデータ交換形式として広く使われていますが、大量のデータを扱うときはデータをフィルタリングしたり整形したりすることが必要になることがあります。今回は、jqコマンドを使ってJSONから特定の項目を取り出し、新しい形式に整形する方法、特定の条件にマッチするレコードのみを選択する方法、そしてmap関数の使い方を紹介します。

    JSONデータの例

    以下に、我々が今回扱うサンプルのJSONデータを示します:

    {
    "records": [
    {
    "id": 1234,
    "user": {
    "id": 5678,
    "account": "user1@example.com",
    "status": 0,
    "attributes": []
    },
    "attributes": [
    {
    "values": [
    {
    "value": "2023-01-01T00:00:00"
    }
    ],
    "id": 2,
    "name": "Date"
    },
    {
    "values": [
    {
    "value": "AB01"
    }
    ],
    "id": 1,
    "name": "Code"
    }
    ]
    }
    ],
    "meta": {
    "totalCount": 999,
    "page": 1,
    "countPerPage": 1,
    "maxPage": 999
    }
    }

    このデータには複数のレコードが含まれ、各レコードにはuser情報とattributes情報があります。

    jqコマンドで特定の項目を取得

    今回の目的は、各レコードから特定の項目を取得し、それを新しい形式に整形することです。これを達成するために、jqコマンドを使用します。

    以下に、新しい形式にデータを整形するためのjqコマンドを示します:

    jq '[.records[] | {EmployeeNumber: .user.id, Email: .user.account, GradeDate: .attributes[0].values[0].value, Grade: .attributes[1].values[0].value}]' input.json

    このコマンドは以下の操作を行います:

    1. レコード配列の各要素に対して操作を行います。
      (.records[] |)。
    2. 新しいオブジェクトを作成し、その中に指定のキーと値を設定します({EmployeeNumber: .user.id, Email: .user.account, GradeDate: .attributes[0].values[0].value, Grade: .attributes[1].values[0].value})。
    3. すべての新しいオブジェクトを包含する配列を作成します([…])。

    これにより、各レコードは新しい形式のオブジェクトに変換され、すべてのオブジェクトが配列に格納されます。それぞれのオブジェクトは EmployeeNumber、Email、GradeDate、Grade の 4つのフィールドを持ちます。

    特定の条件にマッチするレコードを選択

    また、jqは特定の条件にマッチするレコードだけを選択するためのフィルタリング機能も提供しています。たとえば、statusが0のレコードだけを選択するには、以下のようにします:

    jq '[.records[] | select(.user.status == 0) | {EmployeeNumber: .user.id, Email: .user.account, GradeDate: .attributes[0].values[0].value, Grade: .attributes[1].values[0].value}]' input.json

    このコマンドではselect(.user.status == 0)を使用して statusが0のレコードだけを選択しています。

    map関数の使い方

    関数は、配列の各要素に関数を適用して新しい配列を作成するためのものです。たとえば、各レコードのattributesの中のvaluesを取り出すには以下のようにします:

    jq '.records[] | .attributes | map(.values[].value)' input.json

    このコマンドでは、まず各レコードのattributesを取り出し(.records[] | .attributes)、それからmap関数を使って各attributesの中のvaluesのvalueを取り出しています(map(.values[].value))。

    結論

    このように、jqコマンドは非常に強力で柔軟なツールであり、JSONデータの検索やフィルタリング、変換に最適です。特にselect関数とmap関数は、データのフィルタリングや変換において非常に便利です。

    様々な場面でのデータ操作に活用してみてください。また、jqのドキュメンテーションは非常に充実していますので、さらに高度な操作を学びたい場合はそちらを参照してみてください。

  • Office365-REST-Python-Clientを使用したOneDriveへの1GBファイルのアップロード

    Office365-REST-Python-Clientを使用したOneDriveへの1GBファイルのアップロード

    クラウドストレージのOneDriveにファイルを自動的にアップロードする方法について話します。特にPythonを使ったアプローチに焦点を当てます。この記事は、開発者、データサイエンティスト、またはOneDriveを活用して効率を上げたい人向けに書かれています。

    前提条件

    このチュートリアルでは、Python 3.6以上がインストールされていることを前提とします。また、必要なPythonパッケージをインストールするためにpipも必要です。これらがまだインストールされていない場合は、公式のPythonウェブサイトからダウンロードしてください。

    必要なパッケージ

    まず最初に、このプロジェクトで必要となるPythonパッケージをインストールしましょう。今回はOffice365のREST APIクライアントライブラリを使用します。このパッケージは、OneDriveとの連携を容易にします。以下のコマンドを実行してパッケージをインストールしましょう:

    pip install Office365-REST-Python-Client

    この操作はスクリプトを実行する前に行ってください。

    Pythonスクリプトの作成

    以下に、Pythonを使用してOneDriveにファイルをアップロードするための基本的なスクリプトを提供します。

    (インデントが崩れてしまってすみません。。)

    from office365.runtime.auth.user_credential import UserCredential
    from office365.runtime.client_request_exception import ClientRequestException
    from office365.onedrive.driveitems.drive_item import DriveItem
    from office365.graph_client import GraphClient
    from office365.runtime.auth.authentication_context import AuthenticationContext
    import os
    
    
    def get_onedrive_context_using_user():
    tenant = "xxxxxxxxxx"
    authority_url = f"https://login.microsoftonline.com/{tenant}"
    client_id = "xxxxxxxxxx"
    client_secret = "password"
    
    context_auth = AuthenticationContext(authority_url)
    context_auth.acquire_token_for_app(client_id, client_secret)
    
    client = GraphClient(context_auth)
    return client
    
    
    def create_onedrive_directory(client, dir_name: str):
    """
    Creates a folder in the OneDrive directory.
    """
    if dir_name:
    drive_item = DriveItem(client)
    drive_item.name = dir_name
    drive_item.folder = {"childCount": 0}
    return client.me.drive.root.children.add(drive_item)
    
    
    local_path = "1G.csv"
    dir_name = 'test-tsukada-dir-hoge'
    chunk_size = 50000000
    
    def print_upload_progress(range_pos):
    print("{0} bytes uploaded".format(range_pos))
    
    try:
    client = get_onedrive_context_using_user()
    create_onedrive_directory(client, dir_name)
    remote_drive = client.me.drive.root.get_by_path(dir_name)
    
    with open(local_path, 'rb') as f:
    remote_drive.resumable_upload(f, chunk_size=chunk_size, chunk_uploaded=print_upload_progress).get().execute_query()
    print(f"File {local_path} has been uploaded")
    except ClientRequestException as ex:
    print(ex)

    このスクリプトは OneDrive 上のルートにフォルダを作成し、指定したファイルをそのフォルダにアップロードします。アップロードの進行状況はコールバック関数print_upload_progress を用いて表示します。

    ただし、このコードは Azure AD のアプリ登録で取得した client_id と client_secret を使用していますので、それぞれ適切な値に置き換えてください。また、Azure AD のテナントIDも必要となります。

    スクリプトの実行

    スクリプトを実行するには、以下のコマンドをターミナルまたはコマンドプロンプトから実行します:

    python upload_to_onedrive.py

    これで、指定したファイルがOneDriveに自動的にアップロードされます!

    まとめ

    Pythonを使用してOneDriveにファイルを自動アップロードする方法について解説しました。この方法は、定期的なバックアップ、大量のファイルの移行、または一般的なファイルの管理など、さまざまなシナリオで役立ちます。

  • PandasとSnowflakeでNULL値を扱う

    PandasとSnowflakeでNULL値を扱う

    PandasとSnowflakeでNULL値を扱う

    PythonのPandasライブラリとSnowflakeデータベースの間でデータを移動させる場合、 NULL値の扱いはしばしば問題になります。 この記事では、Pandasのデータフレーム内でのNULL値の表現と、 その値をSnowflakeに書き込む方法を説明します。

    PandasでのNULL値

    Pandasでは、データフレーム内の欠損値は None または numpy.nan で表現されます。 これらの値は、数値データだけでなく日付/時刻データに対しても使用できます。 以下のコードスニペットは、データフレームの特定の位置に numpy.nan を設定する方法を示しています。

    import numpy as np
    
    # Set a value in the TIMESTAMP_NTZ column to NaN
    df.loc[0, 'your_timestamp_column'] = np.nan

    このコードは、データフレームの ‘your_timestamp_column’ 列の0行目の値を numpy.nan に設定します。

    NULL値をSnowflakeに書き込む

    PandasからSnowflakeへのデータの書き込みは、 Snowflake-connector-pythonの write_pandas 関数を使用して行うことができます。 この関数は、Pandasの Nonenumpy.nan の値をSnowflakeの NULL として解釈します。 以下のコードスニペットは、上で修正したデータフレームをSnowflakeに書き込む方法を示しています。

    from snowflake.connector.pandas_tools import write_pandas
    
    # Then write the DataFrame to Snowflake
    write_pandas(sf_conn, df, snowflake_table)

    このコードは、sf_conn(Snowflakeへの接続)を使用して、データフレーム dfsnowflake_table という名前のテーブルに書き込みます。 この方法により、Pandasデータフレーム内でNULL値を簡単に扱い、その値をSnowflakeに適切に書き込むことができます。 以上、PythonとPandas、そしてSnowflakeを活用してデータをより柔軟に扱う方法についてお伝えしました。

  • SQL: Null値の扱い方 – COALESCE関数を使った実践的なガイド

    SQL: Null値の扱い方 – COALESCE関数を使った実践的なガイド

    データベースを操作するとき、null値をどのように扱うかは一般的な問題です。実際、Nullはデータが存在しないことを示し、これが意図的である場合もあれば、データが不足しているためである場合もあります。したがって、null値を適切に処理することはデータ管理の重要な部分です。 今日は、SQLのCOALESCE関数を用いたnull値の扱い方について解説します。COALESCE関数は、引数のリストから最初の非null値を返します。

    COALESCE関数とは?

    COALESCE関数は、引数リストから最初の非null値を返すSQLの関数です。COALESCE関数は、以下のように使用します:

    COALESCE(value1, value2, ..., valueN)

    value1からvalueNまでの値が順番に評価され、最初の非null値が返されます。すべての値がnullの場合、COALESCE関数はnullを返します。

    COALESCE関数の具体的な使用例

    例として、以下のテーブルを考えてみましょう。

    CREATE TABLE Employees (
    id INT PRIMARY KEY,
    firstName VARCHAR(100),
    lastName VARCHAR(100),
    email VARCHAR(100)
    );

    このテーブルで、firstNameとlastNameのどちらかがnullの場合に、その代わりに’email not provided’という文字列を表示したいとします。この場合、COALESCE関数を使用できます。

    SELECT id, COALESCE(firstName, 'email not provided') AS firstName, COALESCE(lastName, 'email not provided') AS lastName FROM Employees;

    これにより、firstNameまたはlastNameがnullの場合、その値の代わりに’email not provided’と表示されます。

    数値データに対するCOALESCE関数の使用

    COALESCE関数は数値データにも適用できます。たとえば、ある数値の列がnullの場合、その代わりに0を表示したいとします。この場合もCOALESCE関数を使用できます。

    SELECT id, COALESCE(salary, 0) AS salary FROM Employees;

    これにより、salaryがnullの場合、その値の代わりに0が表示されます。

    まとめ

    COALESCE関数はSQLの強力なツールであり、null値を簡単に扱うことができます。適切なデフォルト値を設定することで、データの一貫性を維持しつつ、欠損データを適切に扱うことができます。SQLのクエリにCOALESCE関数を組み込むことで、データ分析やレポート生成のプロセスをよりスムーズに、より効率的に進めることが可能になります。 また、特定のデータタイプに対して特定のデフォルト値を設定することも可能です。例えば、数値型がnullの場合には0を、文字列型がnullの場合には空文字列(”)をデフォルト値とするなど、データの種類により異なる扱い方をすることができます。

    SELECT
    COALESCE(NENDO, '') AS NENDO,
    COALESCE(HANKI, '') AS HANKI,
    COALESCE(OROSI_DAIHYO_CD, '') AS OROSI_DAIHYO_CD,
    COALESCE(MSDSH_HANTEI_JISSEKI_NEW, 0) AS MSDSH_HANTEI_JISSEKI_NEW,
    FROM YOUR_TABLE;

    以上のように、COALESCE関数を使用すると、一貫性を保ったままかつ効率的にデータベース内のnull値を扱うことができます。COALESCE関数のこのような特性は、データベース操作の質を向上させ、データ解析の正確性を保つ上で重要な役割を果たします。


    これで、SQLのCOALESCE関数についての基本的なガイドと具体的な使用例を提供しました。この記事が、日々のデータベース操作で遭遇する可能性のあるnull値の問題に対する理解と解決の助けになることを願っています。COALESCE関数をうまく使いこなして、より洗練されたデータ処理を実現していけたら幸いです。

  • No space left on device エラーへの対処法

    No space left on device エラーへの対処法

    概要

    今回は、Pythonパッケージのインストール時に遭遇する可能性のある一つの問題、 「No space left on device」エラーとその対処法について説明します。 このエラーが発生する場合、最初に疑うべきは、確かにストレージ容量が足りていない可能性です。 しかし、たとえストレージに十分な空き容量がある場合でも、特定の状況下ではこのエラーが発生します。その解決方法を説明します。

    解決策への道筋

    Pythonパッケージのダウンロードやインストール時に、一時的なファイルが作成されます。 これらの一時的なファイルは通常 /tmp ディレクトリに保存され、大規模なパッケージをインストールする際に /tmp の容量を超えてしまうことがあります。これがエラーの原因となります。 解決策としては、一時ファイルの保存場所を /tmp から別のディレクトリに変更します。これは、環境変数 TMPDIR を設定することで実現します:

    export TMPDIR=/var/tmp

    そして、再度パッケージのインストールを試みます:

    pip3 install --no-cache-dir accelerate

    注意点として、この変更は現在のシェルセッションにのみ適用されます。システム全体への恒久的な変更を行いたい場合は、適切な設定ファイル(例えば ~/.bashrc~/.bash_profile)に上記の export 行を追加します。

    まとめ

    本記事では、「No space left on device」エラーが発生する原因と対処法について解説しました。 この情報が皆様の問題解決の一助となり、よりスムーズにPythonを利用してビジネスを推進する助けとなれば幸いです。