sql >> データベース >  >> RDS >> Database

Pythonを使用したデータエンジニアのインタビューの質問

    面接に行くことは時間と労力のかかるプロセスになる可能性があり、技術面接はさらにストレスを感じる可能性があります。このチュートリアルは、データエンジニアのインタビュー中に遭遇するいくつかの一般的な質問に備えることを目的としています。データベース、Python、SQLに関する質問に答える方法を学びます。

    このチュートリアルを終了すると、次のことができるようになります。

    • 一般的なデータエンジニアの面接の質問を理解する
    • リレーショナルデータベースと非リレーショナルデータベースを区別する
    • Pythonを使用してデータベースを設定する
    • データのクエリにPythonを使用する

    無料ダウンロード: Python Tricks:The Bookからサンプルの章を入手して、Pythonのベストプラクティスと、より美しい+Pythonicコードをすぐに適用できる簡単な例を示します。


    データエンジニアになる

    データエンジニアリングの役割は、広大で多様なものになる可能性があります。複数のテクノロジーと概念に関する実用的な知識が必要です。データエンジニアは柔軟に考えることができます。その結果、データベース、ソフトウェア開発、DevOps、ビッグデータなどの複数のトピックに習熟することができます。


    データエンジニアは何をしますか?

    その多様なスキルセットを考えると、データエンジニアリングの役割は多くの異なる職務記述書にまたがることができます。データエンジニアは、データベースの設計、スキーマの設計、および複数のデータベースソリューションの作成を担当できます。この作業には、データベース管理者も関与する場合があります。

    データエンジニアとして 、データベースとデータサイエンスチームの間の架け橋として機能する場合があります。その場合、データのクリーニングと準備も担当します。ビッグデータが関係している場合、そのデータの効率的なソリューションを考え出すのはあなたの仕事です。この作業は、DevOpsの役割と重複する可能性があります。

    また、レポートと分析のために効率的なデータクエリを作成する必要があります。複数のデータベースを操作したり、ストアドプロシージャを作成したりする必要がある場合があります。トラフィックの多いWebサイトやサービスなどの多くのソリューションでは、複数のデータベースが存在する場合があります。このような場合、データエンジニアはデータベースの設定、保守、データベース間のデータ転送を担当します。



    Pythonはデータエンジニアをどのように支援できますか?

    Pythonは、プログラミング言語のスイスアーミーナイフとして知られています。これは、データサイエンス、バックエンドシステム、サーバーサイドスクリプトで特に役立ちます。これは、Pythonには強い型付け、単純な構文、および使用するサードパーティライブラリが豊富にあるためです。 Pandas、SciPy、Tensorflow、SQLAlchemy、およびNumPyは、さまざまな業界で本番環境で最も広く使用されているライブラリの一部です。

    最も重要なことは、Pythonによって開発時間が短縮されるため、企業の費用が削減されることです。データエンジニアの場合、ほとんどのコード実行はデータベースにバインドされており、CPUにバインドされていません。このため、C#やJavaなどのコンパイル型言語と比較してパフォーマンスが低下するという犠牲を払っても、Pythonのシンプルさを利用することは理にかなっています。




    データエンジニアへのインタビューの質問への回答

    自分の役割が何で構成されているかがわかったので、データエンジニアの面接の質問に答える方法を学びましょう。カバーすべき多くの根拠がありますが、チュートリアル全体を通して実用的なPythonの例を見て、その過程をガイドします。



    リレーショナルデータベースに関する質問

    データベースは、システムで最も重要なコンポーネントの1つです。それらがなければ、国家も歴史もあり得ません。データベース設計を優先事項とは考えていなかったかもしれませんが、それがページの読み込み速度に大きな影響を与える可能性があることを知っておいてください。過去数年間で、いくつかの大企業がいくつかの新しいツールと手法を導入しました。

    • NoSQL
    • キャッシュデータベース
    • グラフデータベース
    • SQLデータベースでのNoSQLサポート

    これらおよびその他の手法は、データベースが要求を処理する速度を上げるために考案されました。データエンジニアのインタビューでこれらの概念について話す必要がある可能性が高いので、いくつか質問を見てみましょう!


    Q1:リレーショナルデータベースと非リレーショナルデータベース

    リレーショナルデータベース データがテーブルの形式で保存されるものです。各テーブルにはスキーマがあります 、これは、レコードに必要な列とタイプです。各スキーマには、そのレコードを一意に識別する少なくとも1つの主キーが必要です。つまり、データベースに重複する行はありません。さらに、各テーブルは外部キーを使用して他のテーブルに関連付けることができます。

    リレーショナルデータベースの重要な側面の1つは、スキーマの変更をすべてのレコードに適用する必要があることです。これにより、移行中に破損や大きな頭痛の種が発生することがあります。 非リレーショナルデータベース 別の方法で物事に取り組みます。これらは本質的にスキーマレスです。つまり、レコードは異なるスキーマと異なるネストされた構造で保存できます。レコードは引き続き主キーを持つことができますが、スキーマの変更はエントリごとに行われます。

    実行する機能のタイプに基づいて、速度比較テストを実行する必要があります。 INSERTを選択できます 、UPDATEDELETE 、または別の関数。スキーマの設計、インデックス、集計の数、レコードの数もこの分析に影響を与えるため、徹底的にテストする必要があります。これを行う方法については、後で詳しく説明します。

    データベースもスケーラビリティが異なります 。非リレーショナルデータベースは、配布するのにそれほど頭痛の種ではないかもしれません。これは、関連するレコードのコレクションを特定のノードに簡単に保存できるためです。一方、リレーショナルデータベースはより多くの検討を必要とし、通常はマスタースレーブシステムを利用します。



    SQLiteの例

    リレーショナルデータベースとは何かについて答えたので、次はPythonを掘り下げます。 SQLiteは、ローカルマシンで使用できる便利なデータベースです。データベースは単一のファイルであるため、プロトタイピングの目的に最適です。まず、必要なPythonライブラリをインポートして、新しいデータベースを作成します。

    import sqlite3
    
    db = sqlite3.connect(':memory:')  # Using an in-memory database
    cur = db.cursor()
    

    これでインメモリデータベースに接続され、カーソルオブジェクトの準備が整いました。

    次に、次の3つのテーブルを作成します。

    1. お客様: このテーブルには、主キーと、顧客の名前と名前が含まれます。
    2. アイテム: このテーブルには、主キー、アイテム名、およびアイテム価格が含まれます。
    3. 購入したアイテム :このテーブルには、注文番号、日付、および価格が含まれます。また、ItemsテーブルとCustomerテーブルの主キーにも接続します。

    テーブルがどのように表示されるかがわかったので、先に進んでテーブルを作成できます。

    cur.execute('''CREATE TABLE IF NOT EXISTS Customer (
                    id integer PRIMARY KEY,
                    firstname varchar(255),
                    lastname varchar(255) )''')
    cur.execute('''CREATE TABLE IF NOT EXISTS Item (
                    id integer PRIMARY KEY,
                    title varchar(255),
                    price decimal )''')
    cur.execute('''CREATE TABLE IF NOT EXISTS BoughtItem (
                    ordernumber integer PRIMARY KEY,
                    customerid integer,
                    itemid integer,
                    price decimal,
                    CONSTRAINT customerid
                        FOREIGN KEY (customerid) REFERENCES Customer(id),
                    CONSTRAINT itemid
                        FOREIGN KEY (itemid) REFERENCES Item(id) )''')
    

    cur.execute()にクエリを渡しました 3つのテーブルを作成します。

    最後のステップは、テーブルにデータを入力することです:

    cur.execute('''INSERT INTO Customer(firstname, lastname)
                   VALUES ('Bob', 'Adams'),
                          ('Amy', 'Smith'),
                          ('Rob', 'Bennet');''')
    cur.execute('''INSERT INTO Item(title, price)
                   VALUES ('USB', 10.2),
                          ('Mouse', 12.23),
                          ('Monitor', 199.99);''')
    cur.execute('''INSERT INTO BoughtItem(customerid, itemid, price)
                   VALUES (1, 1, 10.2),
                          (1, 2, 12.23),
                          (1, 3, 199.99),
                          (2, 3, 180.00),
                          (3, 2, 11.23);''') # Discounted price 
    

    各テーブルにいくつかのレコードがあるので、このデータを使用して、さらにいくつかのデータエンジニアのインタビューの質問に答えることができます。



    Q2:SQL集計関数

    集計関数 結果セットに対して数学演算を実行するものです。いくつかの例には、AVGが含まれます 、COUNTMINMAX 、およびSUM 。多くの場合、GROUP BYが必要になります およびHAVING これらの集計を補完する句。便利な集計関数の1つは、AVGです。 、特定の結果セットの平均を計算するために使用できます:

    >>>
    >>> cur.execute('''SELECT itemid, AVG(price) FROM BoughtItem GROUP BY itemid''')
    >>> print(cur.fetchall())
    [(1, 10.2), (2, 11.73), (3, 189.995)]
    

    ここでは、データベースで購入した各アイテムの平均価格を取得しました。 itemidのアイテムであることがわかります 1の 平均価格は10.20ドルです。

    上記の出力を理解しやすくするために、itemidの代わりにアイテム名を表示できます。 :

    >>>
    >>> cur.execute('''SELECT item.title, AVG(boughtitem.price) FROM BoughtItem as boughtitem
    ...             INNER JOIN Item as item on (item.id = boughtitem.itemid)
    ...             GROUP BY boughtitem.itemid''')
    ...
    >>> print(cur.fetchall())
    [('USB', 10.2), ('Mouse', 11.73), ('Monitor', 189.995)]
    

    これで、平均価格が$10.20のアイテムがUSBであることがわかりやすくなりました。 。

    もう1つの便利な集計は、SUMです。 。この機能を使用して、各顧客が費やした合計金額を表示できます。

    >>>
    >>> cur.execute('''SELECT customer.firstname, SUM(boughtitem.price) FROM BoughtItem as boughtitem
    ...             INNER JOIN Customer as customer on (customer.id = boughtitem.customerid)
    ...             GROUP BY customer.firstname''')
    ...
    >>> print(cur.fetchall())
    [('Amy', 180), ('Bob', 222.42000000000002), ('Rob', 11.23)]
    

    平均して、エイミーという名前の顧客は約180ドルを費やしましたが、ロブは11.23ドルしか費やしませんでした!

    インタビュアーがデータベースを気に入っている場合は、ネストされたクエリ、結合タイプ、およびリレーショナルデータベースがクエリを実行するために実行する手順をブラッシュアップすることをお勧めします。



    Q3:SQLクエリの高速化

    速度はさまざまな要因によって異なりますが、主に次のそれぞれがいくつ存在するかによって影響を受けます。

    • 参加
    • 集計
    • トラバーサル
    • 記録

    結合の数が多いほど、複雑さが増し、テーブル内のトラバーサルの数が多くなります。データベースは中間結果もキャッシュする必要があるため、複数のテーブルを含む数千のレコードに対して複数の結合を実行するには、非常にコストがかかります。この時点で、メモリサイズを増やす方法について考え始めるかもしれません。

    速度は、インデックスがあるかどうかによっても影響を受けます データベースに存在します。インデックスは非常に重要であり、テーブルをすばやく検索して、クエリで指定された列に一致するものを見つけることができます。

    インデックスは、挿入時間とストレージのコストが高くなるという犠牲を払ってレコードを並べ替えます。複数の列を組み合わせて、単一のインデックスを作成できます。たとえば、列date およびprice クエリは両方の条件に依存するため、組み合わせることができます。



    Q4:SQLクエリのデバッグ

    ほとんどのデータベースには、EXPLAIN QUERY PLANが含まれています これは、データベースがクエリを実行するために実行する手順を説明しています。 SQLiteの場合、EXPLAIN QUERY PLANを追加することで、この機能を有効にできます。 SELECTの前 ステートメント:

    >>>
    >>> cur.execute('''EXPLAIN QUERY PLAN SELECT customer.firstname, item.title, 
    ...                item.price, boughtitem.price FROM BoughtItem as boughtitem
    ...                INNER JOIN Customer as customer on (customer.id = boughtitem.customerid)
    ...                INNER JOIN Item as item on (item.id = boughtitem.itemid)''')
    ...
    >>> print(cur.fetchall())
    [(4, 0, 0, 'SCAN TABLE BoughtItem AS boughtitem'), 
    (6, 0, 0, 'SEARCH TABLE Customer AS customer USING INTEGER PRIMARY KEY (rowid=?)'), 
    (9, 0, 0, 'SEARCH TABLE Item AS item USING INTEGER PRIMARY KEY (rowid=?)')]
    

    このクエリは、購入したすべてのアイテムの名、アイテムのタイトル、元の価格、および購入した価格を一覧表示しようとします。

    クエリプラン自体は次のようになります。

    SCAN TABLE BoughtItem AS boughtitem
    SEARCH TABLE Customer AS customer USING INTEGER PRIMARY KEY (rowid=?)
    SEARCH TABLE Item AS item USING INTEGER PRIMARY KEY (rowid=?)
    

    Pythonコードのfetchステートメントは説明のみを返し、結果は返さないことに注意してください。これは、EXPLAIN QUERY PLANが原因です。 本番環境での使用を目的としたものではありません。




    非リレーショナルデータベースに関する質問

    前のセクションでは、リレーショナルデータベースと非リレーショナルデータベースの違いを説明し、PythonでSQLiteを使用しました。次に、NoSQLに焦点を当てます。あなたの目標は、その長所、違い、および使用例を強調することです。


    MongoDBの例

    以前と同じデータを使用しますが、今回はデータベースがMongoDBになります。このNoSQLデータベースはドキュメントベースであり、拡張性に優れています。まず最初に、必要なPythonライブラリをインストールする必要があります:

    $ pip install pymongo
    

    また、MongoDBCompassCommunityをインストールすることもできます。データベースの視覚化に最適なローカルIDEが含まれています。これを使用すると、作成されたレコードを表示したり、トリガーを作成したり、データベースの視覚的な管理者として機能したりできます。

    注: このセクションのコードを実行するには、実行中のデータベースサーバーが必要です。設定方法の詳細については、MongoDBとPythonの概要をご覧ください。

    データベースを作成してデータを挿入する方法は次のとおりです。

    import pymongo
    
    client = pymongo.MongoClient("mongodb://localhost:27017/")
    
    # Note: This database is not created until it is populated by some data
    db = client["example_database"]
    
    customers = db["customers"]
    items = db["items"]
    
    customers_data = [{ "firstname": "Bob", "lastname": "Adams" },
                      { "firstname": "Amy", "lastname": "Smith" },
                      { "firstname": "Rob", "lastname": "Bennet" },]
    items_data = [{ "title": "USB", "price": 10.2 },
                  { "title": "Mouse", "price": 12.23 },
                  { "title": "Monitor", "price": 199.99 },]
    
    customers.insert_many(customers_data)
    items.insert_many(items_data)
    

    お気づきかもしれませんが、MongoDBはデータレコードをコレクションに保存します 、Pythonの辞書のリストに相当します。実際には、MongoDBはBSONドキュメントを保存します。



    Q5:MongoDBを使用したデータのクエリ

    BoughtItemを複製してみましょう SQLで行ったように、最初にテーブルを作成します。これを行うには、顧客に新しいフィールドを追加する必要があります。 MongoDBのドキュメントでは、キーワード演算子 set が指定されています 既存のすべてのフィールドを書き込むことなく、レコードを更新するために使用できます:

    # Just add "boughtitems" to the customer where the firstname is Bob
    bob = customers.update_many(
            {"firstname": "Bob"},
            {
                "$set": {
                    "boughtitems": [
                        {
                            "title": "USB",
                            "price": 10.2,
                            "currency": "EUR",
                            "notes": "Customer wants it delivered via FedEx",
                            "original_item_id": 1
                        }
                    ]
                },
            }
        )
    

    customerにフィールドを追加した方法に注目してください 事前にスキーマを明示的に定義せずに。気の利いた!

    実際、わずかに変更されたスキーマで別の顧客を更新できます:

    amy = customers.update_many(
            {"firstname": "Amy"},
            {
                "$set": {
                    "boughtitems":[
                        {
                            "title": "Monitor",
                            "price": 199.99,
                            "original_item_id": 3,
                            "discounted": False
                        }
                    ]
                } ,
            }
        )
    print(type(amy))  # pymongo.results.UpdateResult
    

    SQLと同様に、ドキュメントベースのデータベースでもクエリと集計を実行できます。ただし、機能は構文的にも基本的な実行においても異なる場合があります。実際、MongoDBが$を予約していることに気付いたかもしれません。 $groupなどのレコードに対するコマンドまたは集計を指定する文字 。この動作の詳細については、公式ドキュメントをご覧ください。

    SQLの場合と同じようにクエリを実行できます。まず、インデックスを作成できます:

    >>>
    >>> customers.create_index([("name", pymongo.DESCENDING)])
    

    これはオプションですが、名前の検索が必要なクエリを高速化します。

    次に、昇順で並べ替えられた顧客名を取得できます。

    >>>
    >>> items = customers.find().sort("name", pymongo.ASCENDING)
    

    購入したアイテムを繰り返して印刷することもできます:

    >>>
    >>> for item in items:
    ...     print(item.get('boughtitems'))    
    ...
    None
    [{'title': 'Monitor', 'price': 199.99, 'original_item_id': 3, 'discounted': False}]
    [{'title': 'USB', 'price': 10.2, 'currency': 'EUR', 'notes': 'Customer wants it delivered via FedEx', 'original_item_id': 1}]
    

    データベース内の一意の名前のリストを取得することもできます:

    >>>
    >>> customers.distinct("firstname")
    ['Bob', 'Amy', 'Rob']
    

    データベース内の顧客の名前がわかったので、クエリを作成して顧客に関する情報を取得できます。

    >>>
    >>> for i in customers.find({"$or": [{'firstname':'Bob'}, {'firstname':'Amy'}]}, 
    ...                                  {'firstname':1, 'boughtitems':1, '_id':0}):
    ...     print(i)
    ...
    {'firstname': 'Bob', 'boughtitems': [{'title': 'USB', 'price': 10.2, 'currency': 'EUR', 'notes': 'Customer wants it delivered via FedEx', 'original_item_id': 1}]}
    {'firstname': 'Amy', 'boughtitems': [{'title': 'Monitor', 'price': 199.99, 'original_item_id': 3, 'discounted': False}]}
    

    同等のSQLクエリは次のとおりです。

    SELECT firstname, boughtitems FROM customers WHERE firstname LIKE ('Bob', 'Amy')
    

    構文はわずかに異なる場合がありますが、内部でクエリを実行する方法には大幅な違いがあることに注意してください。これは、SQLデータベースとNoSQLデータベースの間でクエリ構造とユースケースが異なるために予想されます。



    Q6:NoSQLとSQL

    金融規制情報など、絶えず変化するスキーマがある場合、NoSQLはレコードを変更して関連情報をネストできます。ネストの順序が8つある場合に、SQLで実行する必要のある結合の数を想像してみてください。ただし、この状況はあなたが思っているよりも一般的です。

    では、レポートを実行し、その財務データに関する情報を抽出して、結論を推測したい場合はどうでしょうか。この場合、複雑なクエリを実行する必要があり、SQLはこの点で高速になる傾向があります。

    注: SQLデータベース、特にPostgreSQLも、クエリ可能なJSONデータをレコードの一部として挿入できる機能をリリースしました。これは両方の長所を組み合わせることができますが、速度が問題になる場合があります。

    PostgreSQLのJSONタイプの列からJSONフィールドをクエリするよりも、NoSQLデータベースから非構造化データをクエリする方が高速です。決定的な答えを得るために、いつでも速度比較テストを行うことができます。

    それでも、この機能により、追加のデータベースの必要性が減る可能性があります。ピクルス化またはシリアル化されたオブジェクトは、バイナリタイプの形式でレコードに保存され、読み取り時に逆シリアル化される場合があります。

    ただし、測定基準は速度だけではありません。また、トランザクション、原子性、耐久性、スケーラビリティなども考慮に入れる必要があります。 トランザクション 金融アプリケーションでは重要であり、そのような機能が優先されます。

    それぞれ独自の機能を備えたさまざまなデータベースがあるため、各アプリケーションで使用するデータベースについて情報に基づいた決定を下すのはデータエンジニアの仕事です。詳細については、データベーストランザクションに関連するACIDプロパティを確認できます。

    また、データエンジニアのインタビューで、他にどのようなデータベースを知っているかを尋ねられる場合があります。多くの企業で使用されている他のいくつかの関連データベースがあります:

    • エラスティック検索 テキスト検索で非常に効率的です。ドキュメントベースのデータベースを活用して、強力な検索ツールを作成します。
    • イモリDB ZODBとPostgreSQLJSONB機能を組み合わせて、Python対応のNoSQLデータベースを作成します。
    • InfluxDB 時系列アプリケーションでイベントを保存するために使用されます。

    リストは続きますが、これは、利用可能なさまざまなデータベースがすべて、ニッチ産業にどのように対応しているかを示しています。




    キャッシュデータベースに関する質問

    キャッシュデータベース 頻繁にアクセスされるデータを保持します。これらは、メインのSQLデータベースおよびNoSQLデータベースと共存しています。彼らの目的は、負荷を軽減し、リクエストをより迅速に処理することです。


    Redisの例

    長期ストレージソリューションのSQLデータベースとNoSQLデータベースについて説明しましたが、より高速でより迅速なストレージについてはどうでしょうか。データエンジニアは、データベースからデータを取得する速度をどのように変更できますか?

    一般的なWebアプリケーションは、ユーザーのプロファイルや名前など、よく使用されるデータを頻繁に取得します。すべてのデータが1つのデータベースに含まれている場合、ヒット数 データベースサーバーが取得するのは、最優先で不要です。そのため、より高速でより迅速なストレージソリューションが必要です。

    これによりサーバーの負荷が軽減されますが、データエンジニア、バックエンドチーム、およびDevOpsチームにとって2つの問題が発生します。まず、メインのSQLまたはNoSQLデータベースよりも読み取り時間が速いデータベースが必要になります。ただし、両方のデータベースの内容は最終的に一致する必要があります。 (状態の一貫性の問題へようこそ データベース間!お楽しみください。)

    2つ目の問題は、DevOpsが新しいキャッシュデータベースのスケーラビリティや冗長性などについて心配する必要があることです。次のセクションでは、Redisを使用して、このような問題について詳しく説明します。



    Q7:キャッシュデータベースの使用方法

    この質問に答えるのに十分な情報を紹介から得たかもしれません! キャッシュデータベース は、短命、構造化、または非構造化データを保存するために使用される高速ストレージソリューションです。必要に応じてパーティション化およびスケーリングできますが、通常、メインデータベースよりもサイズがはるかに小さくなります。このため、キャッシュデータベースをメモリに常駐させることができ、ディスクから読み取る必要がなくなります。

    注: Pythonで辞書を使用したことがある場合、Redisは同じ構造に従います。これは、SETを実行できるKey-Valueストアです。 およびGET Pythonのdictのようなデータ 。

    リクエストが届くと、最初にキャッシュデータベースをチェックし、次にメインデータベースをチェックします。このようにして、不要で反復的なリクエストがメインデータベースのサーバーに到達するのを防ぐことができます。キャッシュデータベースは読み取り時間が短いため、パフォーマンスが向上するというメリットもあります。

    pipを使用して、必要なライブラリをインストールできます:

    $ pip install redis
    

    次に、IDからユーザーの名前を取得するリクエストについて考えてみましょう。

    import redis
    from datetime import timedelta
    
    # In a real web application, configuration is obtained from settings or utils
    r = redis.Redis()
    
    # Assume this is a getter handling a request
    def get_name(request, *args, **kwargs):
        id = request.get('id')
        if id in r:
            return r.get(id)  # Assume that we have an {id: name} store
        else:
            # Get data from the main DB here, assume we already did it
            name = 'Bob'
            # Set the value in the cache database, with an expiration time
            r.setex(id, timedelta(minutes=60), value=name)
            return name
    

    このコードは、idを使用して名前がRedisにあるかどうかを確認します 鍵。そうでない場合は、名前に有効期限が設定されます。有効期限は、キャッシュの有効期間が短いために使用します。

    では、インタビュアーがこのコードの何が問題になっているのかと尋ねたらどうなるでしょうか。あなたの応答は、例外処理がないということです!データベースには接続の切断などの多くの問題が発生する可能性があるため、これらの例外をキャッチすることを常にお勧めします。




    デザインパターンとETLの概念に関する質問

    大規模なアプリケーションでは、多くの場合、複数のタイプのデータベースを使用します。実際、PostgreSQL、MongoDB、Redisをすべて1つのアプリケーション内で使用することが可能です。難しい問題の1つは、データベース間の状態の変化に対処することです。これにより、開発者は一貫性の問題にさらされます。次のシナリオを検討してください。

    1. データベース#1のが更新されます。
    2. 同じ値 データベース#2は同じままです(更新されません)。
    3. クエリ データベース#2で実行されます。

    今、あなたは一貫性のない時代遅れの結果を手に入れました! 2番目のデータベースから返される結果は、最初のデータベースの更新された値を反映しません。これは任意の2つのデータベースで発生する可能性がありますが、メインデータベースがNoSQLデータベースであり、情報がクエリ目的でSQLに変換される場合に特に一般的です。

    データベースには、そのような問題に取り組むためのバックグラウンドワーカーがいる場合があります。これらの労働者は抽出 1つのデータベースからのデータ、変換 なんらかの方法で、ロード ターゲットデータベースに追加します。 NoSQLデータベースからSQLデータベースに変換する場合、抽出、変換、読み込み(ETL)プロセスは次の手順を実行します。

    1. 抽出: レコードが作成、更新されるなどの場合は常に、MongoDBトリガーがあります。コールバック関数は、別のスレッドで非同期的に呼び出されます。
    2. 変換: レコードの一部が抽出され、正規化されて、SQLに挿入される正しいデータ構造(または行)に配置されます。
    3. 読み込み: SQLデータベースは、バッチで更新されるか、大量の書き込み用の単一のレコードとして更新されます。

    このワークフローは、財務、ゲーム、およびレポートのアプリケーションで非常に一般的です。このような場合、絶えず変化するスキーマにはNoSQLデータベースが必要ですが、レポート、分析、および集計にはSQLデータベースが必要です。


    Q8:ETLの課題

    ETLには、次のようないくつかの難しい概念があります。

    • ビッグデータ
    • 重大な問題
    • 非同期ワーカー
    • タイプマッチング

    リストは続きます!ただし、ETLプロセスのステップは明確で論理的であるため、データエンジニアとバックエンドエンジニアは通常、実装よりもパフォーマンスと可用性に関心があります。

    アプリケーションが1秒あたり数千のレコードをMongoDBに書き込んでいる場合、ETLワーカーは、要求されたフォームでのデータの変換、読み込み、およびユーザーへの配信に対応する必要があります。速度と遅延が問題になる可能性があるため、これらのワーカーは通常、高速言語で記述されています。この部分は通常CPUにバインドされているため、変換ステップにコンパイル済みコードを使用して処理を高速化できます。

    注: マルチプロセッシングとワーカーの分離は、検討したい他のソリューションです。

    CPUを集中的に使用する関数を多数処理している場合は、Numbaを確認することをお勧めします。このライブラリは、実行時に関数を高速化するために関数をコンパイルします。何よりも、これはPythonで簡単に実装できますが、これらのコンパイル済み関数で使用できる関数にはいくつかの制限があります。



    Q9:ビッグデータのデザインパターン

    Amazonがレコメンダーシステムを作成する必要があると想像してみてください ユーザーに適切な製品を提案する。データサイエンスチームにはデータとその多くが必要です。彼らはデータエンジニアであるあなたのところに行き、別のステージングデータベースウェアハウスを作成するように依頼します。そこで、データをクリーンアップして変換します。

    あなたはそのような要求を受け取ることにショックを受けるかもしれません。テラバイトのデータがある場合、そのすべての情報を処理するには複数のマシンが必要になります。データベース集計関数は、非常に複雑な操作になる可能性があります。比較的大きなデータを効率的にクエリ、集計、利用するにはどうすればよいですか?

    Apacheは当初、 map、shuffle、reduceに続くMapReduceを導入していました。 ワークフロー。アイデアは、クラスターとも呼ばれる別々のマシンに異なるデータをマッピングすることです。次に、キーでグループ化されたデータに対して作業を実行し、最後に最終段階でデータを集約できます。

    このワークフローは現在も使用されていますが、最近はSparkを支持して衰退しています。ただし、デザインパターンは、ほとんどのビッグデータワークフローの基礎を形成し、非常に興味深い概念です。詳細については、IBMAnalyticsのMapReduceをご覧ください。



    Q10:ETLプロセスとビッグデータワークフローの一般的な側面

    これはかなり奇妙な質問だと思うかもしれませんが、これは単にコンピュータサイエンスの知識と、全体的な設計の知識と経験を確認するためのものです。

    どちらのワークフローもプロデューサー-コンシューマーに従います パターン。ワーカー(プロデューサー)は、ある種のデータを生成し、それをパイプラインに出力します。このパイプラインは、ネットワークメッセージやトリガーなど、さまざまな形式をとることができます。プロデューサーがデータを出力した後、コンシューマーはそれを消費して利用します。これらのワーカーは通常、非同期で動作し、別々のプロセスで実行されます。

    プロデューサーをETLプロセスの抽出および変換ステップに例えることができます。同様に、ビッグデータでは、マッパー リデューサーがプロデューサーと見なすことができます 事実上消費者です。この関心の分離は、アプリケーションの開発とアーキテクチャ設計において非常に重要で効果的です。




    結論

    おめでとう!あなたは多くの分野をカバーし、いくつかのデータエンジニアの面接の質問に答えました。これで、データエンジニアが身に付けることができるさまざまな帽子について、またデータベース、設計、ワークフローに関するあなたの責任についてもう少し理解できました。

    この知識を身に付ければ、次のことができるようになります:

    • SQL、NoSQL、およびキャッシュデータベースでPythonを使用する
    • ETLおよびクエリアプリケーションでPythonを使用する
    • 設計とワークフローを念頭に置いて、事前にプロジェクトを計画します

    面接の質問はさまざまですが、あなたは複数のトピックに触れ、コンピュータサイエンスのさまざまな分野で枠にとらわれずに考えることを学びました。これで、すばらしいインタビューを行う準備が整いました。



    1. foreach%dopar%+ RPostgreSQL

    2. Java-前日として保存された日付

    3. MySQLとMariaDBとPerconaサーバー:セキュリティ機能の比較

    4. SYSが所有するオブジェクトにトリガーを作成できないのはなぜですか?