ビッグ・データ・サービス3.0.26以前でのJupyterHubの使用

JupyterHubを使用して、ユーザーのグループのビッグ・データ・サービス3.0.26以前のODH 1.xノートブックを管理します。

前提条件

ブラウザからJupyterHubにアクセスする前に、管理者は次を実行する必要があります:

  • ユーザーからの受信接続でノードを使用できるようにします。ノードのプライベートIPアドレスをパブリックIPアドレスにマップする必要があります。あるいは、要塞ホストまたはOracle FastConnectを使用するようにクラスタを設定できます。プライベートIPアドレスを使用したクラスタ・ノードへの接続を参照してください。
  • ノードでポート8000を開くには、ネットワーク・セキュリティ・リストにイングレス・ルールを構成します。セキュリティ・ルールの定義を参照してください。

JupyterHubデフォルト資格証明

ビッグ・データ・サービス3.0.21以前のJupyterHubのデフォルトの管理サインイン資格証明は次のとおりです:

  • ユーザー名: jupyterhub
  • パスワード: Apache Ambari管理パスワード。これは、クラスタの作成時に指定されたクラスタ管理者パスワードです。
  • HAクラスタのプリンシパル名: jupyterhub
  • HAクラスタのkeytab: /etc/security/keytabs/jupyterhub.keytab

ビッグ・データ・サービス3.0.22から3.0.26のJupyterHubのデフォルトの管理サインイン資格証明は次のとおりです。

  • ユーザー名: jupyterhub
  • パスワード: Apache Ambari管理パスワード。これは、クラスタの作成時に指定されたクラスタ管理者パスワードです。
  • HAクラスタのプリンシパル名: jupyterhub/<FQDN-OF-UN1-Hostname>
  • HAクラスタのkeytab: /etc/security/keytabs/jupyterhub.keytab
    :
    Principal name for HA cluster: jupyterhub/pkbdsv2un1.rgroverprdpub1.rgroverprd.oraclevcn.com
              Keytab for HA cluster: /etc/security/keytabs/jupyterhub.keytab 

管理者は、追加のユーザーとそのサインイン資格証明を作成し、それらのユーザーにサインイン資格証明を提供します。詳細は、ユーザーと権限の管理を参照してください。

ノート

他のタイプの管理者であると明示的に言及されていないかぎり、この項で使用されているadministratorまたはadmin (管理者)は、JupyterHubの管理者であるjupyterhubを指します。

JupyterHubへのアクセス

ビッグ・データ・サービス3.0.26以前のクラスタのブラウザからJupyterHubにアクセスします。JupyterHubは、前提条件が満たされた後にブラウザでアクセスされます。
  1. ブラウザ・ウィンドウを開きます。
  2. 次のフォーマットでURLを入力します:
    https://<node_ip_address>:8000

    :

    https://192.0.2.0:8000
  3. 資格証明でサインインします。
    管理者ユーザーの場合: デフォルトの管理資格証明を使用するか、新しい管理者ユーザーを作成します。
    管理者以外のユーザーの場合: 「Sign Up」ページからサインアップします。管理者ユーザーは、新しいサインアップ・ユーザーを認可する必要があります。認可後、ユーザーはサインインできます。

または、「クラスタURL」の「クラスタ詳細」ページからJupyterHubリンクにアクセスできます。

ロード・バランサを作成して、JupyterHubなどのサービスにアクセスするためのセキュアなフロント・エンドを提供することもできます。ロード・バランサを使用したクラスタ上のサービスへの接続を参照してください。

ノートブックの生成

HAクラスタでのノートブックの生成

ユーザーがノートブックを生成するには、前提条件が満たされている必要があります。

  1. JupyterHubにアクセスします。
  2. 管理資格証明でサインインします。この認可は、ユーザーがLinuxホストに存在する場合にのみ機能します。JupyterHubは、ノートブック・サーバーの起動の試行中にLinuxホストでユーザーを検索します。
  3. 「Server Options」ページにリダイレクトされ、Kerberosチケットをリクエストする必要があります。このチケットは、Kerberosプリンシパルとkeytabファイル、またはKerberosパスワードを使用してリクエストできます。クラスタ管理者は、Kerberosプリンシパルとkeytabファイル、またはKerberosパスワードを提供できます。

    Kerberosチケットは、使用するHDFSディレクトリおよびその他のビッグ・データ・サービスにアクセスする必要があります。

HA以外のクラスタでのノートブックの生成

ユーザーがノートブックを生成するには、前提条件が満たされている必要があります。

  1. JupyterHubにアクセスします。
  2. 管理資格証明でサインインします。この認可は、ユーザーがLinuxホストに存在する場合にのみ機能します。JupyterHubは、ノートブック・サーバーの起動の試行中にLinuxホストでユーザーを検索します。

JupyterHubの管理

JupyterHub adminユーザーは、次のタスクを実行して、ビッグ・データ・サービス3.0.26以前のODH 1.xノードでJupyterHubのノートブックを管理できます。

ブラウザを介したJupyterHubの構成

adminとして、JupyterHubを構成できます。

ノート

ビッグ・データ・サービス3.0.26以前のクラスタのブラウザを使用してJupyterHubを構成します。
  1. opcユーザーとして、JupyterHubがインストールされているユーティリティ・ノード(HA (高可用性)クラスタの2番目のユーティリティ・ノード、または非HAクラスタの最初で唯一のユーティリティ・ノード)に接続します。
  2. sudoを使用して、/opt/jupyterhub/jupyterhub_config.pyに格納されているJupyterHub構成を管理します。
    たとえば、JupyterHubのポート番号を変更するには、次のコマンドを実行します
    vi /opt/jupyterhub/jupyterhub_config.py
    # search for c.JupyterHub.bind_url and edit the port number and save
    sudo systemctl restart jupyterhub.service
    sudo systemctl status jupyterhub.service
ブラウザを介したJupyterHubの停止および起動
ノート

Big Data Service 3.0.26以前のクラスタのブラウザでJupyterHubを停止または起動します。

adminとして、メモリーなどのリソースを消費しないように、アプリケーションを停止または無効化できます。予期しない問題や動作が発生した場合は、再起動すると解決することがあります。

  1. opcユーザーとして、JupyterHubがインストールされているユーティリティ・ノード(HA (高可用性)クラスタの2番目のユーティリティ・ノード、または非HAクラスタの最初で唯一のユーティリティ・ノード)に接続します。
  2. sudoを使用して、JupyterHubを起動、停止または再起動します。
    sudo systemctl start jupyterhub.service
    sudo systemctl stop jupyterhub.service
    sudo systemctl restart jupyterhub.service
    sudo systemctl status jupyterhub.service
ノートブック制限の管理

管理者は、ビッグ・データ・サービス・クラスタ内のアクティブなノートブック・サーバーの数を制限できます。

デフォルトでは、アクティブなノートブック・サーバーの数は、ノード内のOCPU数の2倍に設定されます。デフォルトのOCPU制限は3で、デフォルトのメモリー制限は2Gです。アクティブ・ノートブックの最小数のデフォルト設定は10で、アクティブ・ノートブックの最大数は80です。
  1. opcユーザーとして、JupyterHubがインストールされているユーティリティ・ノード(HA (高可用性)クラスタの2番目のユーティリティ・ノード、または非HAクラスタの最初で唯一のユーティリティ・ノード)に接続します。
  2. sudoを使用して、/opt/jupyterhub/jupyterhub_config.pyに格納されているJupyterHub構成を編集します。
    例:
    c.JupyterHub.active_server_limit = 10
    c.Spawner.cpu_limit = 3
    c.Spawner.mem_limit = '2G'
ノートブック・コンテンツ・マネージャの更新
HDFSコンテンツ・マネージャの更新

デフォルトでは、ノートブックはクラスタのHDFSディレクトリに格納されます。

HDFSディレクトリhdfs:///user/<username>/へのアクセス権が必要です。ノートブックはhdfs:///user/<username>/notebooks/に保存されます。

  1. opcユーザーとして、JupyterHubがインストールされているユーティリティ・ノード(HA (高可用性)クラスタの2番目のユーティリティ・ノード、または非HAクラスタの最初で唯一のユーティリティ・ノード)に接続します。
  2. sudoを使用して、/opt/jupyterhub/jupyterhub_config.pyに格納されているJupyterHub構成を管理します。
    c.Spawner.args = ['--ServerApp.contents_manager_class="hdfscm.HDFSContentsManager"']
  3. sudoを使用して、JupyterHubを再起動します。
    sudo systemctl restart jupyterhub.service
オブジェクト・ストレージ・コンテンツ・マネージャの更新

管理者ユーザーは、個々のユーザー・ノートブックをHDFSではなくオブジェクト・ストレージに格納できます。コンテンツ・マネージャをHDFSからオブジェクト・ストレージに変更すると、既存のノートブックはオブジェクト・ストレージにコピーされません。新しいノートブックはオブジェクト・ストレージに保存されます。

  1. opcユーザーとして、JupyterHubがインストールされているユーティリティ・ノード(HA (高可用性)クラスタの2番目のユーティリティ・ノード、または非HAクラスタの最初で唯一のユーティリティ・ノード)に接続します。
  2. sudoを使用して、/opt/jupyterhub/jupyterhub_config.pyに格納されているJupyterHub構成を管理します。必要なキーの生成方法を学習するには、アクセスおよび秘密キーの生成を参照してください。
    c.Spawner.args = ['--ServerApp.contents_manager_class="s3contents.S3ContentsManager"', '--S3ContentsManager.bucket="<bucket-name>"', '--S3ContentsManager.access_key_id="<accesskey>"', '--S3ContentsManager.secret_access_key="<secret-key>"', '--S3ContentsManager.endpoint_url="https://<object-storage-endpoint>"', '--S3ContentsManager.region_name="<region>"','--ServerApp.root_dir=""']
  3. sudoを使用して、JupyterHubを再起動します。
    sudo systemctl restart jupyterhub.service

オブジェクト・ストレージとの統合

ビッグ・データ・サービス・クラスタで使用するために、Sparkとオブジェクト・ストレージを統合します。

JupyterHubで、Sparkによってオブジェクト・ストレージを操作するには、いくつかのシステム・プロパティを定義し、それらをSpark構成のspark.driver.extraJavaOptionおよびspark.executor.extraJavaOptionsプロパティに移入する必要があります。

前提条件

JupyterHubをオブジェクト・ストレージと正常に統合するには、次を実行する必要があります:

  • オブジェクト・ストアにバケットを作成してデータを格納します。
  • オブジェクト・ストレージAPIキーを作成します。
システム・プロパティ値の取得

Spark構成で定義する必要があるプロパティは:

  • TenantID
  • Userid
  • Fingerprint
  • PemFilePath
  • PassPhrase
  • Region

これらのプロパティの値を取得するには:

  1. ナビゲーション・メニューを開き、「アナリティクスとAI」をクリックします。「データ・レイク」で、「ビッグ・データ・サービス」をクリックします。
  2. 「コンパートメント」で、クラスタをホストするコンパートメントを選択します。
  3. クラスタのリストで、JupyterHubを使用しているクラスタをクリックします。
  4. 「リソース」で、「オブジェクト・ストレージAPIキー」をクリックします。
  5. 表示するAPIキーの「アクション」メニューから、「構成ファイルの表示」をクリックします。

構成ファイルには、パスフレーズを除くすべてのシステム・プロパティの詳細が含まれます。オブジェクト・ストレージAPIキーの作成時にパスフレーズが指定されるため、同じパスフレーズを記憶して使用する必要があります。

例: pysparkを使用したPythonカーネルのオブジェクト・ストレージからのデータの格納および読取り
  1. JupyterHubにアクセスします。
  2. 新しいノートブックを開きます。
  3. 次のコマンドをコピーして貼り付け、Sparkに接続します。
    import findspark
    findspark.init()
    import pyspark
  4. 次のコマンドをコピーして貼り付け、指定した構成でSparkセッションを作成します。以前に取得したシステム・プロパティ値を変数に置き換えます。
    from pyspark.sql import SparkSession
    
    spark = SparkSession \
        .builder \
        .enableHiveSupport() \
        .config("spark.driver.extraJavaOptions", "-DBDS_OSS_CLIENT_REGION=<Region> -DBDS_OSS_CLIENT_AUTH_TENANTID=<TenantId> -DBDS_OSS_CLIENT_AUTH_USERID=<UserId> -DBDS_OSS_CLIENT_AUTH_FINGERPRINT=<FingerPrint> -DBDS_OSS_CLIENT_AUTH_PEMFILEPATH=<PemFile> -DBDS_OSS_CLIENT_AUTH_PASSPHRASE=<PassPhrase>")\
        .config("spark.executor.extraJavaOptions" , "-DBDS_OSS_CLIENT_REGION=<Region> -DBDS_OSS_CLIENT_AUTH_TENANTID=<TenantId> -DBDS_OSS_CLIENT_AUTH_USERID=<UserId> -DBDS_OSS_CLIENT_AUTH_FINGERPRINT=<FingerPrint> -DBDS_OSS_CLIENT_AUTH_PEMFILEPATH=<PemFile> -DBDS_OSS_CLIENT_AUTH_PASSPHRASE=<PassPhrase>")\
        .appName("<appname>") \
        .getOrCreate()
  5. 次のコマンドをコピーして貼り付け、オブジェクト・ストレージ・ディレクトリおよびファイルを作成し、Parquet形式でデータを格納します。
    demoUri = "oci://<BucketName>@<Tenancy>/<DirectoriesAndSubDirectories>/"
    parquetTableUri = demoUri + "<fileName>"
    spark.range(10).repartition(1).write.mode("overwrite").format("parquet").save(parquetTableUri)
  6. 次のコマンドをコピーして貼り付け、オブジェクト・ストレージからデータを読み取ります。
    spark.read.format("parquet").load(parquetTableUri).show()
  7. これらのすべてのコマンドを使用してノートブックを実行します。

    Jupyterでのオブジェクト・ストレージへのアクセス

コードの出力が表示されます。コンソールからオブジェクト・ストレージ・バケットに移動し、バケットに作成されたファイルを検索できます。

ユーザーおよび権限の管理

ノートブックを作成し、オプションでJupyterHubを管理できるように、2つの認証メソッドのいずれかを使用してJupyterHubに対してユーザーを認証します。

デフォルトでは、ODH 1.xクラスタはネイティブ認証をサポートします。ただし、JupyterHubおよびその他のビッグ・データ・サービスの認証は、別の方法で処理する必要があります。JupyterHubにサインインするユーザーは、Linuxホストに存在し、HDFSのルート・ディレクトリに対する書込み権限を持っている必要があります。それ以外の場合、ノートブック・プロセスがLinuxユーザーとしてトリガーされると、生成は失敗します。

ネイティブ認証の詳細は、ネイティブ認証を参照してください。

ビッグ・データ・サービス3.0.26以前のLDAP認証の詳細は、LDAP認証を参照してください。

システム固有の認証

ネイティブ認証は、ユーザーを認証するためのJupyterHubユーザー・データベースによって異なります。

ネイティブ認証は、HAクラスタと非HAクラスタの両方に適用されます。ネイティブ・オーセンティケータの詳細は、ネイティブ・オーセンティケータを参照してください。

HAクラスタでユーザーを認可するための前提条件

ネイティブ認証を使用してビッグ・データ・サービスHAクラスタのユーザーを認可するには、これらの前提条件が満たされている必要があります。

  1. ユーザーは、Linuxホストに存在する必要があります。次のコマンドを実行して、クラスタのすべてのノードで新しいLinuxユーザーを追加します。
    # Add linux user
    dcli -C "useradd -d /home/<username> -m -s /bin/bash <username>"
  2. ノートブック・サーバーを起動するには、ユーザーは、プリンシパルおよびkeytabファイルのpath/passwordを提供し、JupyterHubインタフェースからKerberosチケットをリクエストする必要があります。keytabを作成するには、クラスタ管理者は、パスワードおよびkeytabファイルを持つKerberosプリンシパルを追加する必要があります。クラスタの最初のマスター・ノード(mn0)で次のコマンドを実行します。
    # Create a kdc principal with password or give access to existing keytabs.
    kadmin.local -q "addprinc <principalname>"
    Password Prompt: Enter passwrod
     
    # Create a kdc principal with keytab file or give access to existing keytabs.
    kadmin.local -q 'ktadd -k /etc/security/keytabs/<principal>.keytab principal'
  3. 新しいユーザーは、個々のノートブックが/users/<username>/notebooksに格納されるため、HDFSディレクトリ hdfs:///users/<username>にファイルを格納するための正しいRanger権限を持っている必要があります。クラスタ管理者は、Webブラウザで次のURLを開いて、Rangerインタフェースから必要な権限を追加できます。
    https://<un0-host-ip>:6182
  4. 新しいユーザーには、Yarn、Hiveおよびオブジェクト・ストレージでデータの読取りと書込み、およびSparkジョブを実行するための正しい権限が必要です。または、Spark、Yarnおよびその他のサービスに対する明示的な権限を取得せずに、Livy偽装を使用(Livyユーザーとしてビッグ・データ・サービス・ジョブを実行)することもできます。
  5. 次のコマンドを実行して、新しいユーザーにHDFSディレクトリへのアクセス権を付与します。
    # Give access to hdfs directory
    # kdc realm is by default BDSCLOUDSERVICE.ORACLE.COM
    kinit -kt /etc/security/keytabs/hdfs.headless.keytab hdfs-<clustername>@<kdc_realm> 
    sudo su hdfs -c "hdfs dfs -mkdir /user/<username>"
    sudo su hdfs -c "hdfs dfs -chown -R jupy5 /user/<username>"
非HAクラスタでのユーザーの認可の前提条件

ネイティブ認証を使用してビッグ・データ・サービス非HAクラスタのユーザーを認可するには、これらの前提条件が満たされている必要があります。

  1. ユーザーは、Linuxホストに存在する必要があります。次のコマンドを実行して、クラスタのすべてのノードで新しいLinuxユーザーを追加します。
    # Add linux user
    dcli -C "useradd -d /home/<username> -m -s /bin/bash <username>"
  2. 新しいユーザーは、HDFSディレクトリ hdfs:///users/<username>にファイルを格納するための適切な権限を持っている必要があります。次のコマンドを実行して、新しいユーザーにHDFSディレクトリへのアクセス権を付与します。
    # Give access to hdfs directory
    sudo su hdfs -c "hdfs dfs -mkdir /user/<username>"
    sudo su hdfs -c "hdfs dfs -chown -R jupy5 /user/<username>"
管理者ユーザーの追加

管理者ユーザーは、JupyterHubの構成および管理について責任を負います。また、管理者ユーザーは、JupyterHubで新しくサインアップしたユーザーの認可も担当します。

管理者ユーザーを追加するには、HAクラスタまたは非HAクラスタの前提条件が満たされている必要があります。

  1. Apache Ambariにアクセスします。
  2. サイド・ツールバーの「Services」で、JupyterHubをクリックします。
  3. 「Configs」「Advanced Configs」の順にクリックします。
  4. 「Advanced jupyterhub-config」を選択します。
  5. c.Authenticator.admin_usersに管理ユーザーを追加します。
  6. 「保存」をクリックします
JupyterHub構成ファイルの管理ユーザーは、サインイン時に明示的な認可を受ける必要はありません。サインアップ後、直接サインインできます。
他のユーザーの追加

他のユーザーを追加する前に、ビッグ・データ・サービス・クラスタの前提条件を満たす必要があります。

  1. JupyterHubにアクセスします。
  2. 新しいユーザーをサインアップします。管理者以外のユーザーは、管理者ユーザーからの明示的な認可が必要です。
  3. 管理ユーザーは、JupyterHubにサインインし、新しいメニュー・オプションからサインイン・ユーザーを認可する必要があります。
    Jupyterhubの「Authorize Users」ページのスクリーンショット
  4. これで、新しいユーザーはサインインできます。
ユーザーの削除

管理者ユーザーは、JupyterHubユーザーを削除できます。

  1. JupyterHubにアクセスします。
  2. 「File」>HubControlPanelを開きます。
  3. 「Authorize Users」ページに移動します。
  4. 削除するユーザーを削除します。
LDAP認証

ビッグ・データ・サービス3.0.26以前のODH 1.xクラスタのブラウザを介してLDAP認証を使用できます。

Trinoとの統合

前提条件
  • Trinoは、ビッグ・データ・サービス・クラスタにインストールおよび構成されている必要があります。
  • 次のPythonモジュールをJupyterHubノードにインストールします(HAの場合はun1、HA以外のクラスタの場合はun0)
    ノート

    Trino-Pythonモジュールがすでにノードに存在する場合、このステップは無視してください。
    python3.6 -m pip install trino[sqlalchemy]
     
    Offline Installation:
    Download the required python module in any machine where we have internet access
    Example:
    python3 -m pip download trino[sqlalchemy] -d /tmp/package
    Copy the above folder content to the offline node & install the package
    python3 -m pip install ./package/*
     
    Note : trino.sqlalchemy is compatible with the latest 1.3.x and 1.4.x SQLAlchemy versions. 
    BDS cluster node comes with python3.6 and SQLAlchemy-1.4.46 by default.
ビッグ・データ・サービスHAクラスタとの統合

Trino-Ranger-Pluginが有効になっている場合は、提供されているkeytabユーザーをそれぞれのTrino Rangerポリシーに追加してください。TrinoとRangerの統合を参照してください。

デフォルトでは、Trinoは完全なKerberosプリンシパル名をユーザーとして使用します。したがって、trino-rangerポリシーを追加/更新する場合は、ユーザー名として完全なKerberosプリンシパル名を使用する必要があります。

次のコード・サンプルでは、trino-rangerポリシーのユーザーとしてjupyterhub@BDSCLOUDSERVICE.ORACLE.COMを使用します。

ノート

Trino-Ranger-Pluginが有効になっている場合は、指定されたkeytabユーザーをそれぞれのTrino Rangerポリシーに追加してください。詳細は、「TrinoでのRangerの有効化」を参照してください。

JupyterHubのRanger権限を次のポリシーに提供します。

  • all - catalog, schema, table, column
  • all - function
  1. ブラウザ・ウィンドウを開きます。
  2. 次のフォーマットでURLを入力します:
    https://<node_ip_address>:8000

    例:

    https://192.0.2.0:8000
  3. 資格証明でサインインします。JupyterHubデフォルト資格証明を参照してください。
  4. 「原則」および「キータブ」を入力します。
  5. Phython 3ノートブックを開きます。
  6. Trinoでエンジンを作成:
    from sqlalchemy import create_engine
    from sqlalchemy.schema import Table, MetaData
    from sqlalchemy.sql.expression import select, text
    from trino.auth import KerberosAuthentication
    from subprocess import Popen, PIPE
    import pandas as pd
     
    # Provide user specific keytab_path and principal. If user wants to run queries 
    with different keytab then user can update below keytab_path & user_principal 
    else #user can use same keytab_path, principal that is used while starting the 
    notebook session.
    #Refer below sample code
     
    keytab_path='/etc/security/keytabs/jupyterhub.keytab'
    user_principal='jupyterhub@BDSCLOUDSERVICE.ORACLE.COM'
    # Cert path is required for SSL.
    cert_path= '/etc/security/serverKeys/oraclerootCA.crt'
    # trino url = 'trino://<trino-coordinator>:<port>'
    trino_url='trino://trinohamn0.sub03011425120.hubvcn.oraclevcn.com:7778'
     
     
    # This is optional step, required only if user wants to run queries with different keytab.
     
    kinit_args = [ '/usr/bin/kinit', '-kt', keytab_path, user_principal]
    subp = Popen(kinit_args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    subp.wait()
       
    engine = create_engine(
        trino_url,
        connect_args={
            "auth": KerberosAuthentication(service_name="trino", principal=user_principal, ca_bundle=cert_path),
            "http_scheme": "https",
            "verify": True
        }
    )
  7. 問合せを実行:
    query = "select custkey, name, phone, acctbal from tpch.sf1.customer limit 10"
    df = pd.read_sql(query, engine)
    print(df)
ビッグ・データ・サービス非HAクラスタとの統合
  1. ブラウザ・ウィンドウを開きます。
  2. 次のフォーマットでURLを入力します:
    https://<node_ip_address>:8000

    例:

    https://192.0.2.0:8000
  3. 資格証明を使用してログインします。JupyterHubデフォルト資格証明を参照してください。
  4. Phython 3ノートブックを開きます。
  5. Trinoでエンジンを作成:
    from sqlalchemy import create_engine
    from sqlalchemy.schema import Table, MetaData
    from sqlalchemy.sql.expression import select, text
    import pandas as pd
     
    # trino url = 'trino://trino@<trino-coordinator>:<port>'
    trino_url='trino://trino@trinohamn0.sub03011425120.hubvcn.oraclevcn.com:8285'
     
    engine = create_engine(trino_url)
  6. 問合せを実行します。
    query = "select custkey, name, phone, acctbal from tpch.sf1.customer limit 10"
    df = pd.read_sql(query, engine)
    print(df)