Upgrade to Pro — share decks privately, control downloads, hide ads and more …

身近なCSVを活用する!AWSのデータ分析基盤アーキテクチャ

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Kotaro.Sato Kotaro.Sato
November 18, 2025

 身近なCSVを活用する!AWSのデータ分析基盤アーキテクチャ

Avatar for Kotaro.Sato

Kotaro.Sato

November 18, 2025
Tweet

More Decks by Kotaro.Sato

Other Decks in Technology

Transcript

  1. 5 イントロダクション ⚫ なぜCSVなのか ⚫ 身近だから ⚫ 体系的な説明(データ分析基盤の考え方)とHow to(CSVを分析する方法) を両立したいから

    ◼ データ分析基盤は通常、CSV以外のデータも含めた汎用的な分析を目的としている ◼ 一方で分析対象をCSVに主眼に置くことで、体系的かつ具体的な説明になるようにしたい ⚫ データ分析基盤をAWSで構築する理由 ⚫ マネージドな環境で、スモールスタートができるから ⚫ 大規模なデータ処理を想定するなら別だが、最小構成で始めることはそれほど難しくない ⚫ 「データレイク、データウェハウスってこういうもの」を手を動かして理解する
  2. 7 CSVデータを分析するには/データ分析のHow To ⚫「CSVならExcelで分析できるよ」 ⚫ メタデータの収集が困難 ⚫ データのサイロ化(分析用Excelが乱立) ⚫ 仕様上の制約(1,048,576行まで)

    ⚫「BIツールにCSVを放り込めば解決!」 ⚫ CSVは型や制約、リレーションを持たない ⚫ 同じ意味を表現しているはずでもデータ間で「表記ゆれ」のような問題が簡単に起こる 例) 「性別」の表現方法 → 男/女、M/F、0/1、男女というバイナリ表現自体が不適切 … ⚫ データ間の相関分析のようなニーズにそのまま対応することは難しい CustomerId Gender C100 男 C200 回答しない VisitorId Gender V100 M V200 F
  3. 8 CSVデータを分析するには/データ分析の課題 ⚫(課題)CSVは構造化データに見えて、実態はただのテキストで半構造化データ ⚫ このギャップの穴埋めが必要 ⚫ 構造化データを分析するためにはデータの秩序(構造化)が必要 ⚫(だから)データを構造化し、集約する基盤が必要 ⚫ 生データ(そのままのCSV)

    ⚫ 加工データ(構造化されたCSV) ⚫ データを加工するための仕組み(ジョブなどのロジック) ⚫ メタデータ(データに関するデータ) ⚫(そのために、広義の)データ分析基盤を用意する ⚫ 構造化されたデータを扱うデータウェアハウス ←本日の話題 ⚫ 非構造化されたデータ扱うデータレイク
  4. 10 CSVデータを分析するには/データ分析基盤の構成要素(要件) ⚫何があれば「データ分析基盤」と言えるのか? ⚫このセミナーでは以下の機能を指すものとする ⚫ データを取り込む機能 ⚫ データを保存する機能(ストレージ機能) ⚫ データを加工する機能

    ⚫ データを提供する機能 ※BI基盤 ⚫データ分析基盤の構成要素の解像度を上げるためには、以下の説明が必要 ⚫ データエンジニアリングの基礎知識 ⚫ AWSの具体的なサービス
  5. 12 データを加工する機能 オーケストレーション ファイル プログラム ベース データエンジニアリングの基礎/サービスマップ ⚫ 本日お話しするサービスの全容(取り込み→ストレージ→加工→提供) ストレージ機能

    データを取り込む機能 データを提供する機能 フォーマット 保存場所 構造化データ 半構造化データ 非構造化データ データベース SQLベース GUIベース
  6. 13 データを加工する機能 オーケストレーション ファイル プログラム ベース データエンジニアリングの基礎/サービスマップ ⚫ 本日お話しするサービスの全容(取り込み→ストレージ→加工→提供) ストレージ機能

    データを取り込む機能 データを提供する機能 フォーマット 保存場所 構造化データ 半構造化データ 非構造化データ データベース SQLベース GUIベース
  7. 14 データエンジニアリングの基礎/データを取り込む機能/概要 ⚫データは自分で動かない。必ずデータを誰かに送ってもらうか、自分から取りにいく機能が必要 ⚫ プッシュ:基盤にデータをプッシュしてもらう=データ基盤分析はそのインターフェースを作る ⚫ プル:基盤からデータを取りにいく ⚫どこからデータを取ってくる? ⚫ 社内:

    SFTPサーバ、DBサーバ、社内システムが提供するREST APIなど ⚫ 社外: Webサービスが提供しているREST APIなどが中心(気象情報や祝日などのオープンデータも含む) ⚫何のデータを取ってくる? ⚫ ここではCSVを前提とするが、DBのテーブルやAPIから取得したデータなども典型的な取り込み対象 サーバ(社内) API/DB/SFTP サーバ データ分析 基盤 サーバ(社外) (主に)APIサーバ プル プッシュ プル プッシュ HTTP(GET)/JDBC/SCP データ データ HTTP(POST)/SFTP ※このパターンはあまりない HTTP(GET)
  8. 16 データを加工する機能 オーケストレーション ファイル プログラム ベース データエンジニアリングの基礎/サービスマップ ⚫ 本日お話しするサービスの全容(取り込み→ストレージ→加工→提供) ストレージ機能

    データを取り込む機能 データを提供する機能 フォーマット 保存場所 構造化データ 半構造化データ 非構造化データ データベース SQLベース GUIベース
  9. 17 データエンジニアリングの基礎/ストレージ機能/概要 ⚫データをどこに、どのような形式で保存するか?の検討が必要 = ストレージ機能 ⚫CSVは半構造化データにあたるが、分析には構造化データへの加工が必要。両者の保存方法の検討が必要 ⚫ 構造化データ…(DBMSのテーブルなど) ⚫ 半構造化データ…(JSON/XML/CSVなど)

    ⚫ 非構造化データ…(TXTなど) ⚫構造化データにあって、半構造化データにないものは? ⚫ カラム定義、型、制約、リレーション ⚫ データに秩序を持たせ、性質を説明するデータ→(狭義の)メタデータ ⚫ これらのデータをどこに持たせるか?の検討も必要 構造化データ 半構造化データ カラム定義、型、制約、リレーション カラム、値 ←(狭義の)メタデータ ← データ 非構造化データ バイト配列(バイナリ)
  10. 18 データエンジニアリングの基礎/ストレージ機能/どこに保存する? ⚫半構造化データ(そのままのCSV) ⚫ オブジェクトストレージ(以下、S3)に保存する ⚫構造化データ(加工されたCSV) ⚫ 加工(後述)のプロセスを経て、CSVを構造化するためのパターン ⚫ S3

    + Glue Data Catalogに構造化して保存するパターン ◼ データにアクセスするためのインターフェースはAthenaになる ◼ データ: S3に持たせる ◼ メタデータ: Glue Data Catalogに持たせる ⚫ データウェアハウス(以下、Redshift)に構造化して保存するパターン ◼ データにアクセスするためのインターフェースはRedshiftになる ◼ データ/メタデータともにRedshiftにプロビジョニングされたストレージにテーブルとして持たせる
  11. 21 データエンジニアリングの基礎/ストレージ機能/保存パターンの比較 ⚫主な違いは従量課金 vs. 時間課金 ⚫どちらがベストになるかは実行が想定されるクエリの頻度および規模をベースに考える ⚫ 頻度の多いクエリ: 参照頻度、加工頻度、分析対象データの量(数と容量) ◼

    BIのキャッシュ機能(QuickSightだとSPICE)を使い参照頻度を抑える方法もある ⚫ 規模の大きいクエリ: 年単位のデータ集計、複雑なデータ加工ロジックを持つクエリなど ◼ パフォーマンス/コストの両面でRedshiftに軍配が上がりやすいケース S3 + Glue Data Catalog Redshift 備考 データ(CSV)の保存先 S3 S3 + Redsihft メタデータの保存先 Glue Data Catalog Redshift 課金の考え方 データ量(S3) + 従量 (Athenaでスキャンが発生したデータ量な ど) データ量(S3) + 時間 (Redshiftのプロビジョニング時間な ど) Redshift Serverlessによる計算コ ストの最適化 スケーラビリティ 動的 静的 or 動的(Serverless) ユースケース 小規模なクエリの実行 大量のデータ参照を必要とする 複雑なクエリの実行
  12. 22 データを加工する機能 オーケストレーション ファイル プログラム ベース データエンジニアリングの基礎/サービスマップ ⚫ 本日お話しするサービスの全容(取り込み→ストレージ→加工→提供) ストレージ機能

    データを取り込む機能 データを提供する機能 フォーマット 保存場所 構造化データ 半構造化データ 非構造化データ データベース SQLベース GUIベース
  13. 23 データエンジニアリングの基礎/データを加工する機能/概要 ⚫データにビジネス上の洞察を得るための意味を持たせるためのプロセス ⚫ 半構造化データを構造化データにする ⚫ データの表記を整える ⚫ データに情報を加える ⚫

    意味付けを行う(標準偏差などの統計情報の付加やラベリング) ⚫乳牛(ソース)から搾乳した(取り込んだ)乳(データ)を牛乳(意味のあるデータ)に変えるまでのプロセス 乳牛 データ分析基盤 牛乳 包装 検査 殺菌
  14. 24 データエンジニアリングの基礎/データを加工する機能/サービスの選び方 ⚫データの加工にはどのようなロジック(反復可能な仕組み)が必要か ⚫ 加工ロジック:データを加工するためのロジック(汎用的) ◼ 「名寄せ」「正規化」「結合」「ピボット」…(後述) ⚫ ビジネスロジック:ビジネス上の手続きや暗黙知を反映させたロジック(非汎用的) ◼

    「集計ジョブの実行は平日日中帯だけにしたい。祝日は対象外で」 ◼ 「店舗の売上をブロック毎に集計したい。売上と客数に基づいて店舗ランク情報を付与する」 ⚫GUI vs. SQL vs. プログラム どのように実装するか ⚫ 汎用性と保守性を重視するか、学習コストを重視するか 学習コスト (初学の場合) 保守性 汎用性 ユースケース GUI 低 (ツールによる) 中 (実装次第・ 仕様の制約) 低 (仕様の制約) ・スモールスタートで始めたい場合 SQL 中 (宣言型) 高 (実装次第) 中 (関数に依存) ・加工ロジックが比較的シンプルな場合 ・データソースがDBのみである場合 プログラム 高 (手続き型) 高 (実装次第) 高 (実装次第) ・加工条件に複雑なビジネスロジックを含む場合 ・データソースにDB以外を含む場合
  15. 25 データエンジニアリングの基礎/データを加工する機能/典型的な加工パターン ⚫名寄せ ⚫ 同じ意味を持つ文字の表記を統一する Original Name 佐藤商店株式会社 東京都新宿区西新宿1-1 Original

    Name ㈱佐藤商店 東京都新宿区西新宿1-1 ⚫ピボット/アンピボット ⚫ 行で持つ情報を列で持つ情報に変換(逆も) ⚫正規化 ⚫ データ間で形式や単位を統一する Date Sales_S001 2025-11-10 150000 Date Store_ID Sales 2025-11-10 S001 150000 ↑アンピボット ↓ピボット ↓変換 ⚫結合(JOIN) ⚫ テーブル間に共通するキーでテーブル同士を 結合する Date 2025/11/10 11-12-2025 Nov. 15, 2025 Date 2025-11-10 2025-11-12 2025-11-15 変換→ OrderId ItemId Quantity O100 P01 2 O200 P02 1 ItemId ItemName P01 コーヒー豆 P02 マグカップ ItemIdで結合→
  16. 26 データエンジニアリングの基礎/データを加工する機能/典型的な加工パターン ⚫名寄せ ⚫ 同じ意味を持つ文字の表記を統一する Original Name 佐藤商店株式会社 東京都新宿区西新宿1-1 Original

    Name ㈱佐藤商店 東京都新宿区西新宿1-1 ⚫ピボット/アンピボット ⚫ 行で持つ情報を列で持つ情報に変換(逆も) ⚫正規化 ⚫ データ間で形式や単位を統一する Date Sales_S001 2025-11-10 150000 Date Store_ID Sales 2025-11-10 S001 150000 ↑アンピボット ↓ピボット ↓変換 ⚫結合(JOIN) ⚫ テーブル間に共通するキーでテーブル同士を 結合する Date 2025/11/10 11-12-2025 Nov. 15, 2025 Date 2025-11-10 2025-11-12 2025-11-15 変換→ OrderId ItemId Quantity O100 P01 2 O200 P02 1 ItemId ItemName P01 コーヒー豆 P02 マグカップ ItemIdで結合→
  17. 27 データエンジニアリングの基礎/データを加工する機能/典型的な加工パターン ⚫名寄せ ⚫ 同じ意味を持つ文字の表記を統一する Original Name 佐藤商店株式会社 東京都新宿区西新宿1-1 Original

    Name ㈱佐藤商店 東京都新宿区西新宿1-1 ⚫ピボット/アンピボット ⚫ 行で持つ情報を列で持つ情報に変換(逆も) ⚫正規化 ⚫ データ間で形式や単位を統一する Date Sales_S001 2025-11-10 150000 Date Store_ID Sales 2025-11-10 S001 150000 ↑アンピボット ↓ピボット ↓変換 ⚫結合(JOIN) ⚫ テーブル間に共通するキーでテーブル同士を 結合する Date 2025/11/10 11-12-2025 Nov. 15, 2025 Date 2025-11-10 2025-11-12 2025-11-15 変換→ OrderId ItemId Quantity O100 P01 2 O200 P02 1 ItemId ItemName P01 コーヒー豆 P02 マグカップ ItemIdで結合→
  18. 28 データエンジニアリングの基礎/データを加工する機能/典型的な加工パターン ⚫名寄せ ⚫ 同じ意味を持つ文字の表記を統一する Original Name 佐藤商店株式会社 東京都新宿区西新宿1-1 Original

    Name ㈱佐藤商店 東京都新宿区西新宿1-1 ⚫ピボット/アンピボット ⚫ 行で持つ情報を列で持つ情報に変換(逆も) ⚫正規化 ⚫ データ間で形式や単位を統一する Date Sales_S001 2025-11-10 150000 Date Store_ID Sales 2025-11-10 S001 150000 ↑アンピボット ↓ピボット ↓変換 ⚫結合(JOIN) ⚫ テーブル間に共通するキーでテーブル同士を 結合する Date 2025/11/10 11-12-2025 Nov. 15, 2025 Date 2025-11-10 2025-11-12 2025-11-15 変換→ OrderId ItemId Quantity O100 P01 2 O200 P02 1 ItemId ItemName P01 コーヒー豆 P02 マグカップ ItemIdで結合→
  19. 29 データエンジニアリングの基礎/データを加工する機能/メダリオンアーキテクチャ ⚫加工は意味別に3段階に分けることで、ロジックが疎結合になり汎用性が高まる ⚫ Bronze: 生のデータ(取り込み) ⚫ Silver: データの正規化や表記揺れ修正などのクレンジング済データ ⚫

    Gold: Silverテーブル同士のJOINや情報付加などを経てBIに提供するデータ →Goldはデータマートに相当(目的に最適化された情報) 情報量 汎用性 信頼性 Bronze 多 高 低 Silver 中 中 高 Gold 少 低 高
  20. 31 データエンジニアリングの基礎/データを加工する機能/オーケストレーション/サービス ⚫AWS Step Functions ⚫ AWS操作を汎用的にワークフロー化できる ⚫ GUIベースのワークフロー ◼

    汎用性はStep Functionsの仕様に依存 ⚫ 加工が全てAWSで完結する場合に最適 ⚫Amazon Managed Workflow for Apache Airflow ⚫ Apache Airflowをマネージドに利用できる ⚫ Pythonベースのワークフロー(DAG) ◼ 汎用性の高いワークフロー設計 ⚫ AWS外の操作を必要とする場合に最適 引用: https://docs.aws.amazon.com/ja_jp/step- functions/latest/dg/concepts-statemachines.html 引用: https://aws.amazon.com/jp/blogs/news/introducing- amazon-managed-workflows-for-apache-airflow-mwaa/
  21. 32 データエンジニアリングの基礎/データを加工する機能/(Tips)Step Functionsについて ⚫実際のところ、Step Functionsでどこまで制御できるのか? ⚫ 拙作『詳解 AWS Step Functions:

    プログラム言語のように記法を理解しよう』を参照 ◼ https://blog.serverworks.co.jp/2025/10/21/160754 ⚫ 一般的なプログラム言語が持つ基本的な制御はカバーしています!(条件分岐、並列、ループ…) Redshiftのクエリ実行を制御するイメージ 並列実行をするイメージ
  22. 33 データを加工する機能 オーケストレーション ファイル プログラム ベース データエンジニアリングの基礎/サービスマップ ⚫ 本日お話しするサービスの全容(取り込み→ストレージ→加工→提供) ストレージ機能

    データを取り込む機能 データを提供する機能 フォーマット 保存場所 構造化データ 半構造化データ 非構造化データ データベース SQLベース GUIベース
  23. 34 データエンジニアリングの基礎/データを提供する機能/概要 ⚫加工されたデータを消費者(人間やBI基盤)に提供する機能 ⚫何を提供する? ⚫ データカタログ(基盤が取り扱うデータを示すもの) ⚫ データ ◼ 未加工のデータ(Bronze)

    ◼ クレンジングされたデータ(Silver) ◼ データマート(Gold) ⚫ ガバナンス ◼ データのアクセス権限 ◼ データリネージ(いつ、どこから取得されたデータなのか) ⚫ インターフェース ◼ UI画面 ◼ API ◼ データベースインターフェース
  24. 35 データエンジニアリングの基礎/データを提供する機能/消費者としてのBIがどう機能するか ⚫逆に、消費者の目線ではデータ分析基盤をどのように利用している? ⚫ 消費者の一例として、BIサービスのAmazon Quick Suite(旧Amazon QuickSight)では? ⚫Qucik Suiteの基本概念と、データ分析基盤との接続インターフェース

    ⚫ データソース:参照したいデータを見に行くための権限や接続情報 ⚫ データセット:データソースからQuick Suiteに取り込んだデータ ⚫ 分析:データセットに対して集計や視覚化などの加工をしたデータ ⚫ ダッシュボード:分析を1枚のパネルに集めた定義情報
  25. 36 データエンジニアリングの基礎/データを提供する機能/消費者としてのBIがどう機能するか ⚫逆に、消費者の目線ではデータ分析基盤をどのように利用している? ⚫ 消費者の一例として、BIサービスのAmazon Quick Suite(旧Amazon QuickSight)では? ⚫Qucik Suiteの基本概念と、データ分析基盤との接続インターフェース

    ⚫ データソース:参照したいデータを見に行くための権限や接続情報 ⚫ データセット:データソースからQuick Suiteに取り込んだデータ ⚫ 分析:データセットに対して集計や視覚化などの加工をしたデータ ⚫ ダッシュボード:分析を1枚のパネルに集めた定義情報 データソース データセット 分析 ダッシュ ボード
  26. 38 アーキテクチャパターン/概要 ⚫アーキテクチャ=以下の機能をどのように実現するか ⚫ データを取り込む機能 ⚫ データを保存する機能(ストレージ機能) ⚫ データを加工する機能 ⚫

    データを提供する機能 ※BI基盤 ⚫何を重視するか ⚫ ランニングコスト ⚫ パフォーマンス ⚫ 開発コスト(スクラッチ開発部分を減らす) ⚫3パターンの構成を紹介 ⚫ パターン1: S3+Athena+Step Functions ⚫ パターン2: Redshift ⚫ パターン3: サードパーティ(Databricks on AWS)
  27. 44 アーキテクチャパターン/サードパーティ(Databricks on AWS) <データ処理の流れ> ①:バッチ処理でSFTPサーバ→AWSにソースデータ(CSV)をアップロード ②:ソースデータをDatabricksにロードし、DatabricksにDelta Lake Tableとして保存 Databricks内で表記揺れ修正などのデータ成型→データ結合などのBI用途の加工

    ③: QuickSightが加工されたデータをDatabricksのAPIキーを使って参照し、可視化 ストレージ データを 加工する 機能 データを 取り込む 機能 ・操作はDatabricksが提供する専用のWeb UIから ・データを置くのは利用者のAWS環境 →利便性(UI)とガバナンスを両立するSaaS型 データを 提供する 機能
  28. 45 アーキテクチャパターン/比較 S3+Athena+Step Functions Redshift サードパーティ(Databricks on AWS) アーキテクチャ (疑似的な)データウェアハウス

    データウェアハウス レイクハウス データレイク S3 S3 S3(Delta Lake Volume) データウェアハウス S3 + Glue Data Catalog Redsihft S3(Delta Lake Table) 非構造化データの分析 不可 不可 可 データカタログ Glue Data Catalog Glue Data Catalog Databirkcs(Unity Catalog) ワークフロー Step Functions Step Functions Databricks(Job) データ操作言語 SQL (プログラムからSQL実行は可) SQL (プログラムからSQL実行は可) SQL/Python/Scala/R データのアクセス権限管理 Athena WorkGroup Redshift Databirkcs(Unity Catalog) BI Quick Suite Quick Suite Databricks(Dashboard) or Quick Suite 規模 小規模 中~大規模 小~大規模 ユースケース 構造化データの分析 構造化データの分析 構造化データの分析 非・半構造化データの分析(機械学習)
  29. 49 デモ/加工のイメージ transa ction_ id store_ id sales_ dateti me

    amou nt paym ent_m ethod gende r points _used year month day SMT00 01202 51101 0001 SMT00 01 2025- 11-01 16:46: 27.000 2191 現金 女性 0 2025 11 1 SMT00 01202 51101 0001 SMT00 01 2025- 11-01 16:46: 27.000 2191 現金 女性 0 store_id store_name postal_code year month day SM0001 サーバーマート 丸の内一丁目店 100-0005 2025 10 31 SM0001 サーバーマート 丸の内一丁目店 100-0005 transa ction_ id store_ id sales_ dateti me amou nt paym ent_m ethod gende r points _used year month day SMT00 01202 51101 0001 SM00 01 2025- 11-01 16:46: 27.000 2191 現金 女性 0 2025 11 1 store_id store_name postal_code year month day SM0001 サーバーマート 丸の内一丁目店 100-0005 2025 10 31 transaction_i d store_id sales_dateti me amount payment_me thod gender points_used store_name postal_code year month day SMT00012025 11010001 SM0001 2025-11-01 16:46:27.000 2191 現金 女性 0 サーバーマート 丸の内一丁目店 100-0005 2025 11 1 ↓Athenaのパーティション情報(year, month, day)を追加 ↓store_masterに合わせたstore_idの名寄せ(SMT→SM)/Parquetで保存 ↓ Parquetで保存 ↓store_id, year, month, dayでJOIN(LEFT OUTER JOIN) /Parquetで保存↓ 元データ (CSV) Bronze Silver Gold ※ヘッダ無し ※ヘッダ無し
  30. 50 デモ/S3のバケット構成のイメージ ⚫bronze_pos_dataは手動でアップロード(実運用を想定するとデータソース側でバッチ処理が必要) ⚫データの物理的な保存先は以下の通り、日次で堆積される swx-handson-csv-<Account Id>/ ├── bronze_pos_data/ │ └──

    year=2025/ │ ├── month=10/ │ │ └── day=31/ │ │ └── pos_sales.csv │ └── month=11/ │ └── day=01/ │ └── pos_sales.csv ├── bronze_store_master/ │ └── year=2025/ │ ├── month=10/ │ │ └── day=31/ │ │ └── mst_store_master.csv │ └── month=11/ │ └── day=01/ │ └── mst_store_master.csv ├── silver_pos_data/ │ └── year=2025/ │ └── month=10/ │ └── day=31/ │ └── <Parquetファイル> │ └── month=11/ │ └── day=01/ │ └── <Parquetファイル> ├── silver_store_master/ │ └── year=2025/ │ └── month=10/ │ └── day=31/ │ └── <Parquetファイル> │ └── month=11/ │ └── day=01/ │ └── <Parquetファイル> ├── gold_pos_data_analysis/ │ └── year=2025/ │ └── month=10/ │ └── day=31/ │ └── <Parquetファイル> │ └── month=11/ │ └── day=01/ │ └── <Parquetファイル> └── query-results/ └── <クエリの実行結果が保存される>
  31. 52 デモ/Goldテーブルの集計イメージ(Athena) ⚫2025/10/31の客数が多かった店舗TOP10を出してみる SELECT store_id, store_name, year, month, day, FLOOR(AVG(amount))

    as avg_sales_amount, COUNT(*) as total_customers FROM analysis_handson_gold.pos_data_analysis WHERE year = 2025 AND month = 10 AND day = 31 GROUP BY store_id, store_name, year, month, day ORDER BY total_customers DESC LIMIT 10;