Files
CSIROBoeingPhase5-Vietnam/ODC.ipynb
T
2026-04-04 02:16:36 +00:00

496 lines
20 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "ac069784-fbb6-48c8-a547-11b96cade97b",
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true,
"source_hidden": true
},
"scrolled": true
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_218/1243805045.py:22: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n",
" df = pd.read_sql(sql, conn)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" product_name total_images\n",
"0 s2_l2a 2074896\n",
"1 sentinel_2_c1_l2a 1137446\n",
"2 landsat7_c2l2_sr 169065\n",
"3 landsat7_c2l2_st 168410\n",
"4 landsat8_c2l2_sr 122846\n",
"5 landsat8_c2l2_st 120778\n",
"6 landsat5_c2l2_sr 118583\n",
"7 landsat5_c2l2_st 118406\n",
"8 landsat8_c2l1 111513\n",
"9 nasa_aqua_l2_oc 37232\n",
"10 landsat9_c2l2_sr 30214\n",
"11 landsat9_c2l2_st 29709\n",
"12 landsat9_c2l1 18875\n",
"13 nasa_aqua_l2_sst 12070\n",
"14 ga_ls_mangrove_cover_cyear_3 5580\n",
"15 sentinel1_grd_gamma0_10m_unsmooth 5488\n",
"16 sentinel1_grd_gamma0_20m 4260\n",
"17 copernicus_dem_30 1334\n",
"18 global_mangrove_soc_2020_30m 784\n",
"19 global_mangrove_soc_2000_30m 781\n",
"20 global_mangrove_canopy_height_2015_12m 761\n",
"21 sentinel1_grd_gamma0_10m 291\n",
"22 lpdaac_nasadem 264\n",
"23 cci_biomass_annual_v51 248\n",
"24 esa_worldcover_2020 184\n",
"25 esa_worldcover_2021 184\n",
"26 global_tidal_marsh_soc_30m 41\n",
"27 global_tidal_marsh_distribution_2020_10m 35\n",
"28 copernicus_dem_fiji 26\n",
"29 lpdaac_mod11a1v061_lste 2\n",
"30 global_mangrove_soc_2000_100m 1\n"
]
}
],
"source": [
"import psycopg2\n",
"import os\n",
"import pandas as pd\n",
"\n",
"# Kết nối (như cũ)\n",
"conn = psycopg2.connect(\n",
" host=os.environ.get('DB_HOSTNAME'),\n",
" user=os.environ.get('DB_USERNAME'),\n",
" password=os.environ.get('DB_PASSWORD'),\n",
" dbname=os.environ.get('DB_DATABASE')\n",
")\n",
"\n",
"# Đếm số lượng ảnh theo từng loại sản phẩm\n",
"sql = \"\"\"\n",
"SELECT t.name as product_name, count(*) as total_images\n",
"FROM agdc.dataset d\n",
"JOIN agdc.dataset_type t ON d.dataset_type_ref = t.id\n",
"GROUP BY t.name\n",
"ORDER BY total_images DESC;\n",
"\"\"\"\n",
"\n",
"df = pd.read_sql(sql, conn)\n",
"print(df)\n",
"conn.close()"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a0ae4051-3bfd-49fd-83fe-4c31c74338e2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Đang kết nối trực tiếp tới PostgreSQL...\n",
"Kết nối thành công!\n",
"\n",
"--> Đang xuất bảng: agdc.metadata_type\n",
" Đã lưu xong: metadata_type.csv\n",
"--> Đang xuất bảng: agdc.dataset_type\n",
" Đã lưu xong: dataset_type.csv\n",
"--> Đang xuất bảng: agdc.dataset_location\n",
" Đã lưu xong: dataset_location.csv\n",
"--> Đang xuất bảng: agdc.dataset\n",
" Đã lưu xong: dataset.csv\n",
"\n",
"HOÀN TẤT! Bạn hãy tải 4 file CSV về máy.\n"
]
}
],
"source": [
"import psycopg2\n",
"import os\n",
"\n",
"# 1. Lấy thông tin kết nối\n",
"db_host = os.environ.get('DB_HOSTNAME')\n",
"db_user = os.environ.get('DB_USERNAME')\n",
"db_pass = os.environ.get('DB_PASSWORD')\n",
"db_name = os.environ.get('DB_DATABASE')\n",
"\n",
"# 2. Danh sách các bảng cần lấy\n",
"tables = [\n",
" 'agdc.metadata_type',\n",
" 'agdc.dataset_type',\n",
" 'agdc.dataset_location',\n",
" 'agdc.dataset'\n",
"]\n",
"\n",
"print(\"Đang kết nối trực tiếp tới PostgreSQL...\")\n",
"\n",
"try:\n",
" # Kết nối trực tiếp (Bỏ qua Pandas/SQLAlchemy)\n",
" conn = psycopg2.connect(\n",
" host=db_host,\n",
" user=db_user,\n",
" password=db_pass,\n",
" dbname=db_name\n",
" )\n",
" cur = conn.cursor()\n",
" print(\"Kết nối thành công!\\n\")\n",
"\n",
" for table_name in tables:\n",
" print(f\"--> Đang xuất bảng: {table_name}\")\n",
" \n",
" # Tên file CSV đầu ra\n",
" file_name = table_name.split('.')[1] + \".csv\"\n",
" \n",
" # Sử dụng lệnh COPY chuyên dụng của Postgres (Cực nhanh và chuẩn)\n",
" # SQL: COPY (SELECT * FROM table) TO STDOUT WITH CSV HEADER\n",
" sql = f\"COPY (SELECT * FROM {table_name}) TO STDOUT WITH CSV HEADER\"\n",
" \n",
" with open(file_name, 'w') as f:\n",
" cur.copy_expert(sql, f)\n",
" \n",
" print(f\" Đã lưu xong: {file_name}\")\n",
"\n",
" cur.close()\n",
" conn.close()\n",
" print(\"\\nHOÀN TẤT! Bạn hãy tải 4 file CSV về máy.\")\n",
"\n",
"except Exception as e:\n",
" print(f\"\\nCÓ LỖI XẢY RA: {e}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d139879e-c350-4986-a2e6-0d59099eb770",
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true,
"source_hidden": true
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Đang kết nối...\n",
"Kết nối thành công! Đang ước lượng nhanh...\n",
"\n",
"--- BẢNG DỰ TÍNH DUNG LƯỢNG (ƯỚC LƯỢNG) ---\n",
"NĂM | SỐ ẢNH (ƯỚC TÍNH) | SIZE (CSV) \n",
"------------------------------------------------------------\n",
"2020 | ~ 21,448 | ~ 83.78 MB\n",
"2021 | ~ 21,448 | ~ 83.78 MB\n",
"2022 | ~ 21,448 | ~ 83.78 MB\n",
"2023 | ~ 21,448 | ~ 83.78 MB\n",
"2024 | ~ 21,448 | ~ 83.78 MB\n",
"------------------------------------------------------------\n",
"TỔNG CỘNG : ~ 107,240 ảnh (Khoảng 418.91 MB)\n",
"------------------------------------------------------------\n",
"(Lưu ý: Số liệu này là ước tính của Database, độ chính xác khoảng 80-90%)\n"
]
},
{
"name": "stdin",
"output_type": "stream",
"text": [
"\n",
"Bạn có muốn bắt đầu tải không? (y/n): y\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
">>> Đang tải bảng định nghĩa...\n",
"\n",
">>> Đang tải dữ liệu chính...\n",
"--> Năm 2020...\n"
]
}
],
"source": [
"import psycopg2\n",
"import os\n",
"import re # Thư viện xử lý chuỗi để lấy số liệu\n",
"\n",
"# --- CẤU HÌNH ---\n",
"YEARS = [2020, 2021, 2022, 2023, 2024]\n",
"AVG_ROW_SIZE_KB = 4 \n",
"\n",
"db_host = os.environ.get('DB_HOSTNAME')\n",
"db_user = os.environ.get('DB_USERNAME')\n",
"db_pass = os.environ.get('DB_PASSWORD')\n",
"db_name = os.environ.get('DB_DATABASE')\n",
"\n",
"print(\"Đang kết nối...\")\n",
"\n",
"try:\n",
" conn = psycopg2.connect(\n",
" host=db_host, user=db_user, password=db_pass, dbname=db_name\n",
" )\n",
" cur = conn.cursor()\n",
" print(\"Kết nối thành công! Đang ước lượng nhanh...\\n\")\n",
"\n",
" # ==========================================\n",
" # BƯỚC 1: ƯỚC LƯỢNG SIÊU TỐC (INSTANT ESTIMATE)\n",
" # ==========================================\n",
" print(\"--- BẢNG DỰ TÍNH DUNG LƯỢNG (ƯỚC LƯỢNG) ---\")\n",
" print(f\"{'NĂM':<10} | {'SỐ ẢNH (ƯỚC TÍNH)':<20} | {'SIZE (CSV)':<20}\")\n",
" print(\"-\" * 60)\n",
"\n",
" total_est_rows = 0\n",
"\n",
" for year in YEARS:\n",
" # Mẹo: Dùng EXPLAIN để lấy số liệu ước tính từ Query Planner\n",
" # Nó sẽ trả về chuỗi kiểu: \"Seq Scan on dataset ... (rows=12345 ...)\"\n",
" sql_estimate = f\"\"\"\n",
" EXPLAIN SELECT 1 FROM agdc.dataset\n",
" WHERE (metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01'\n",
" AND (metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
" \"\"\"\n",
" cur.execute(sql_estimate)\n",
" explain_result = cur.fetchone()[0] # Lấy dòng đầu tiên của kết quả EXPLAIN\n",
" \n",
" # Dùng Regex để bắt lấy con số sau chữ \"rows=\"\n",
" match = re.search(r\"rows=(\\d+)\", explain_result)\n",
" if match:\n",
" count = int(match.group(1))\n",
" else:\n",
" count = 0 # Không bắt được số\n",
" \n",
" total_est_rows += count\n",
" est_size_mb = (count * AVG_ROW_SIZE_KB) / 1024\n",
" \n",
" print(f\"{year:<10} | ~ {count:<18,} | ~ {est_size_mb:.2f} MB\")\n",
"\n",
" print(\"-\" * 60)\n",
" print(f\"TỔNG CỘNG : ~ {total_est_rows:,} ảnh (Khoảng {(total_est_rows * AVG_ROW_SIZE_KB)/1024:.2f} MB)\")\n",
" print(\"-\" * 60)\n",
" print(\"(Lưu ý: Số liệu này là ước tính của Database, độ chính xác khoảng 80-90%)\")\n",
"\n",
" # ==========================================\n",
" # QUYẾT ĐỊNH TẢI\n",
" # ==========================================\n",
" check = input(\"\\nBạn có muốn bắt đầu tải không? (y/n): \")\n",
" if check.lower() != 'y':\n",
" print(\"Đã hủy.\")\n",
" exit()\n",
"\n",
" # ==========================================\n",
" # BƯỚC 2 & 3: TẢI DỮ LIỆU (Giữ nguyên logic cũ)\n",
" # ==========================================\n",
" # ... (Phần code tải small_tables và tải dữ liệu chính giữ nguyên như cũ) ...\n",
" # Để code gọn, mình viết tiếp phần tải ở dưới đây:\n",
" \n",
" # 2. Tải bảng nhỏ\n",
" print(\"\\n>>> Đang tải bảng định nghĩa...\")\n",
" for tb in ['agdc.metadata_type', 'agdc.dataset_type']:\n",
" f_name = tb.split('.')[1] + \".csv\"\n",
" with open(f_name, 'w') as f:\n",
" cur.copy_expert(f\"COPY (SELECT * FROM {tb}) TO STDOUT WITH CSV HEADER\", f)\n",
" \n",
" # 3. Tải dữ liệu chính\n",
" print(\"\\n>>> Đang tải dữ liệu chính...\")\n",
" for year in YEARS:\n",
" print(f\"--> Năm {year}...\")\n",
" \n",
" # Dataset\n",
" f_ds = f\"dataset_{year}.csv\"\n",
" sql_ds = f\"\"\"\n",
" COPY (SELECT * FROM agdc.dataset \n",
" WHERE (metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01' \n",
" AND (metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
" ) TO STDOUT WITH CSV HEADER\"\"\"\n",
" with open(f_ds, 'w') as f: cur.copy_expert(sql_ds, f)\n",
" \n",
" # Location\n",
" f_loc = f\"dataset_location_{year}.csv\"\n",
" sql_loc = f\"\"\"\n",
" COPY (SELECT l.* FROM agdc.dataset_location l JOIN agdc.dataset d ON l.dataset_ref = d.id\n",
" WHERE (d.metadata->'properties'->>'datetime')::timestamp >= '{year}-01-01' \n",
" AND (d.metadata->'properties'->>'datetime')::timestamp <= '{year}-12-31 23:59:59'\n",
" ) TO STDOUT WITH CSV HEADER\"\"\"\n",
" with open(f_loc, 'w') as f: cur.copy_expert(sql_loc, f)\n",
" \n",
" print(\"\\nHOÀN TẤT TOÀN BỘ!\")\n",
" cur.close()\n",
" conn.close()\n",
"\n",
"except Exception as e:\n",
" print(f\"\\nCÓ LỖI: {e}\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "8a5bb199-9363-47cc-9640-bf7e0af33d19",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Đang quét kho dữ liệu (Điều này có thể mất 1-2 phút)...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_499/84613258.py:40: UserWarning: pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite3 DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.\n",
" df = pd.read_sql(sql, conn)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"============================================================\n",
"PRODUCT NAME | SỐ LƯỢNG | DUNG LƯỢNG (TB)\n",
"------------------------------------------------------------\n",
"s2_l2a | 2,074,896 | 1621.01 TB\n",
"sentinel_2_c1_l2a | 1,137,446 | 555.39 TB\n",
"landsat7_c2l2_sr | 169,065 | 82.55 TB\n",
"landsat7_c2l2_st | 168,410 | 82.23 TB\n",
"landsat8_c2l2_sr | 122,846 | 59.98 TB\n",
"landsat8_c2l2_st | 120,778 | 58.97 TB\n",
"landsat5_c2l2_sr | 118,583 | 57.90 TB\n",
"landsat5_c2l2_st | 118,406 | 57.82 TB\n",
"landsat8_c2l1 | 111,513 | 54.45 TB\n",
"nasa_aqua_l2_oc | 37,232 | 18.18 TB\n",
"landsat9_c2l2_sr | 30,214 | 14.75 TB\n",
"landsat9_c2l2_st | 29,709 | 14.51 TB\n",
"landsat9_c2l1 | 18,875 | 9.22 TB\n",
"nasa_aqua_l2_sst | 12,070 | 5.89 TB\n",
"ga_ls_mangrove_cover_cyear_3 | 5,580 | 2.72 TB\n",
"sentinel1_grd_gamma0_10m_unsmooth | 5,488 | 2.68 TB\n",
"sentinel1_grd_gamma0_20m | 4,260 | 2.08 TB\n",
"copernicus_dem_30 | 1,334 | 0.65 TB\n",
"global_mangrove_soc_2020_30m | 784 | 0.38 TB\n",
"global_mangrove_soc_2000_30m | 781 | 0.38 TB\n",
"global_mangrove_canopy_height_2015_12m | 761 | 0.37 TB\n",
"sentinel1_grd_gamma0_10m | 291 | 0.14 TB\n",
"lpdaac_nasadem | 264 | 0.13 TB\n",
"cci_biomass_annual_v51 | 248 | 0.12 TB\n",
"esa_worldcover_2020 | 184 | 0.09 TB\n",
"esa_worldcover_2021 | 184 | 0.09 TB\n",
"global_tidal_marsh_soc_30m | 41 | 0.02 TB\n",
"global_tidal_marsh_distribution_2020_10m | 35 | 0.02 TB\n",
"copernicus_dem_fiji | 26 | 0.01 TB\n",
"lpdaac_mod11a1v061_lste | 2 | 0.00 TB\n",
"global_mangrove_soc_2000_100m | 1 | 0.00 TB\n",
"------------------------------------------------------------\n",
"TỔNG CỘNG TOÀN SERVER : ~ 2702.76 TB (Terabytes)\n",
"Tương đương : ~ 2767622 GB\n",
"============================================================\n"
]
}
],
"source": [
"import psycopg2\n",
"import os\n",
"import pandas as pd\n",
"\n",
"# CẤU HÌNH: Ước lượng dung lượng trung bình cho mỗi cảnh ảnh (Đơn vị: GB)\n",
"# Đây là con số kinh nghiệm thực tế:\n",
"AVG_SIZE_GB = {\n",
" 's2_l2a': 0.8, # Sentinel-2 L2A (Khoảng 800MB/cảnh)\n",
" 'ga_s2_gm': 0.1, # Geomedian (Ảnh tổng hợp, nhẹ hơn)\n",
" 'ls5_sr': 0.5, # Landsat 5 (Nhẹ hơn S2)\n",
" 'ls7_sr': 0.6, # Landsat 7\n",
" 'ls8_sr': 1.0, # Landsat 8 (Nặng hơn)\n",
" 'ls9_sr': 1.0, # Landsat 9\n",
" 'wofs_albers': 0.05, # Water Observation (Chỉ là mask nước, rất nhẹ)\n",
" 'default': 0.5 # Mặc định nếu không biết loại nào\n",
"}\n",
"\n",
"# Kết nối Database\n",
"db_host = os.environ.get('DB_HOSTNAME')\n",
"db_user = os.environ.get('DB_USERNAME')\n",
"db_pass = os.environ.get('DB_PASSWORD')\n",
"db_name = os.environ.get('DB_DATABASE')\n",
"\n",
"print(\"Đang quét kho dữ liệu (Điều này có thể mất 1-2 phút)...\")\n",
"\n",
"try:\n",
" conn = psycopg2.connect(\n",
" host=db_host, user=db_user, password=db_pass, dbname=db_name\n",
" )\n",
" \n",
" # Query: Đếm số lượng ảnh theo từng loại Product\n",
" sql = \"\"\"\n",
" SELECT t.name as product_name, count(*) as total_images\n",
" FROM agdc.dataset d\n",
" JOIN agdc.dataset_type t ON d.dataset_type_ref = t.id\n",
" GROUP BY t.name\n",
" ORDER BY total_images DESC;\n",
" \"\"\"\n",
" \n",
" df = pd.read_sql(sql, conn)\n",
" \n",
" # Tính toán dung lượng\n",
" def estimate_size(row):\n",
" # Tìm size trong từ điển, nếu không có thì lấy default\n",
" size_per_scene = AVG_SIZE_GB.get(row['product_name'], AVG_SIZE_GB['default'])\n",
" return row['total_images'] * size_per_scene\n",
"\n",
" df['total_size_gb'] = df.apply(estimate_size, axis=1)\n",
" df['total_size_tb'] = df['total_size_gb'] / 1024\n",
" \n",
" # Hiển thị báo cáo\n",
" print(\"\\n\" + \"=\"*60)\n",
" print(f\"{'PRODUCT NAME':<25} | {'SỐ LƯỢNG':<10} | {'DUNG LƯỢNG (TB)':<15}\")\n",
" print(\"-\" * 60)\n",
" \n",
" for index, row in df.iterrows():\n",
" print(f\"{row['product_name']:<25} | {row['total_images']:<10,} | {row['total_size_tb']:.2f} TB\")\n",
" \n",
" print(\"-\" * 60)\n",
" total_tb = df['total_size_tb'].sum()\n",
" print(f\"TỔNG CỘNG TOÀN SERVER : ~ {total_tb:.2f} TB (Terabytes)\")\n",
" print(f\"Tương đương : ~ {total_tb * 1024:.0f} GB\")\n",
" print(\"=\"*60)\n",
"\n",
" conn.close()\n",
"\n",
"except Exception as e:\n",
" print(f\"Lỗi: {e}\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}