Przez kilka dni budowałem lokalny pipeline do pobrania i przetworzenia pełnego datasetu Gaia DR3. Celem było:
- pobranie całej tabeli
gaia_source - konwersja do Parquet
- walidacja integralności danych
- przygotowanie szybkich wizualizacji całego nieba oraz Dużego Obłoku Magellana
Projekt został wykonany lokalnie w Pythonie + Jupyter Notebook z użyciem Parquet, Polars, DuckDB i Plotly.
Stack technologiczny
Środowisko
- Python 3.10 + 3.11
- Jupyter Notebook
- Ubuntu Server
- Szybki dysk SSD NVMe
Biblioteki
- Astroquery
- Astropy
- PyArrow
- Polars
- DuckDB
- Pandas
- Plotly
- Matplotlib
Dwie metody pobierania Gaia DR3
Pobieranie przez SQL ESA TAP
- logowanie do ESA Gaia Archive
- pobieranie batchami po 100 000 rekordów
- checkpointy
- retry logic
- zapis do Parquet
Pobierane były tylko wybrane kolumny:
- source_id
- ra
- dec
- l
- b
- parallax
- pmra
- pmdec
- phot_g_mean_mag
- phot_bp_mean_mag
- phot_rp_mean_mag
- ruwe
Cechy kodu crawlera:
- możliwość wznawiania pobierania
- wykładnicze opóźnienie ponownych prób
- logowanie nieudanych batchy / paczek danych
- automatyczny zapis checkpointów
- konwersję float64 -> float32
- batching do parquetów
Problem SQL
SQL okazał się zbyt wolny dla pełnego datasetu.
Pobranie około 500 milionów rekordów trwało około 3 dni — i to tylko dla ograniczonego zestawu parametrów. Pobranie jednego batchu 100 000 rekordów i konwersja do parquetu trwała 15 sekund w dni wolne, oraz 50-60 sekund w dni pracujące.
To było zbyt wolne dla pełnego Gaia DR3.
Pobieranie bezpośrednio z CDN ESA
Finalnie przeszedłem na oficjalny CDN Gaia DR3.
To okazało się znacznie szybsze i stabilniejsze.
Jest to równocześnie rekomendowana metoda pobierania całego datasetu przez ESA.
Pipeline CDN -> Parquet
Crawler wykonywał:
- Pobranie oficjalnego
_MD5SUM.txt - Parsowanie listy plików
- Pobieranie wszystkich
.csv.gz - Walidację MD5
- Odczyt ECSV
- Konwersję Arrow -> Parquet
- Kompresję ZSTD
- Checkpointing
- Cleanup
Kod zawierał:
- mechanizm ponownych prób
- walidacja sum kontrolnych MD5
- możliwość wznawiania sesji pobierania
- automatyczne checkpointy
- obsługę nulli
- silnik pyarrow
- kompresję ZSTD
Podczas budowy pipeline konieczne było utworzenie oddzielnego środowiska Conda specjalnie do pobierania danych z CDN Gaia DR3.
starsze wersje Astropy nie obsługują poprawnie:
read_ecsv()- engine=
pyarrow
dla dużych plików Gaia DR3 ECSV.
Dopiero:
- Python 3.11
- Astropy 7+
- nowy PyArrow
pozwalały stabilnie odczytywać ogromne pliki .csv.gz bezpośrednio jako ECSV.
Pipeline korzystał z:
read_ecsv(
csv_path,
engine="pyarrow",
null_values=["null"]
)
Pobranie jednej paczki 500 000 rekordów, walidacja i zapis do parquet z wszystkimi kolumnami trwało około 60 sekund.
Walidacja integralności danych
Wynik walidacji
Liczba plików
- znaleziono: 3386
- oczekiwano: 3386
- brakujących: 0
Rozmiar
- około 600.61 GB parquetów
Liczba rekordów
- rows: 1,811,709,771
- expected: 1,811,709,771
- difference: 0
Duplikaty
- duplicates: 0
Unikalne source_id
- unique_source_ids: 1,811,709,771
============================================================
FILE COUNT
============================================================
FOUND: 3,386
EXPECTED: 3,386
MISSING: 0
============================================================
TOTAL SIZE
============================================================
600.61 GB
============================================================
FULL DATASET VALIDATION
============================================================
ROWS: 1,811,709,771
EXPECTED: 1,811,709,771
ROW DIFFERENCE: 0
UNIQUE SOURCE_ID: 1,811,709,771
DUPLICATES: 0
RA RANGE: 0.0000 -> 360.0000
DEC RANGE: -89.9929 -> 89.9901
L RANGE: 0.0000 -> 360.0000
B RANGE: -89.9937 -> 89.9880
SOURCE_ID NULLS: 0
RA NULLS: 0
DEC NULLS: 0
PARALLAX NULLS: 343,964,953
============================================================
VALIDATION COMPLETE
============================================================
============================================================
Sprawdzono również pokrycie nieba RA, DEC, L, B, NULLS i PARALLAX NULLS. Liczba rekordów bez paralaksy odpowiada zbiorowi rekordów dwu-parametrowych co stwierdza się również poniżej.
Zgodność z oficjalnym datasetem ESA
============================================================
RUNNING SCIENTIFIC VALIDATION
============================================================
============================================================
OFFICIAL ESA VS LOCAL DATASET
============================================================
total_sources LOCAL: 1,811,709,771 ESA: 1,811,709,771 DIFF: 0 100.00% OK
sources_with_g LOCAL: 1,806,254,432 ESA: 1,806,254,432 DIFF: 0 100.00% OK
sources_with_bp LOCAL: 1,542,033,472 ESA: 1,542,033,472 DIFF: 0 100.00% OK
sources_with_rp LOCAL: 1,554,997,939 ESA: 1,554,997,939 DIFF: 0 100.00% OK
sources_with_full_astrometry LOCAL: 1,467,744,818 ESA: 1,467,744,818 DIFF: 0 100.00% OK
five_parameter_sources LOCAL: 585,416,709 ESA: 585,416,709 DIFF: 0 100.00% OK
six_parameter_sources LOCAL: 882,328,109 ESA: 882,328,109 DIFF: 0 100.00% OK
two_parameter_sources LOCAL: 343,964,953 ESA: 343,964,953 DIFF: 0 100.00% OK
============================================================
VALIDATION COMPLETE
============================================================
| # sources in Gaia DR3 | |
|---|---|
| Total number of sources | 1,811,709,771 |
| Gaia Early Data Release 3 | |
| Number of sources with full astrometry | 1,467,744,818 |
| Number of 5-parameter sources | 585,416,709 |
| Number of 6-parameter sources | 882,328,109 |
| Number of 2-parameter sources | 343,964,953 |
| Gaia-CRF sources | 1,614,173 |
| Sources with mean G magnitude | 1,806,254,432 |
| Sources with mean GBP-band photometry | 1,542,033,472 |
| Sources with mean GRP-band photometry | 1,554,997,939 |
Walidacja kolumn posługując się plikiem referencyjnym.
============================================================
GAIA SCHEMA VALIDATION
============================================================
FILES FOUND: 3,386
============================================================
LOADING REFERENCE SCHEMA
============================================================
REFERENCE FILE:
GaiaSource_000000-003111.parquet
COLUMNS: 152
============================================================
VALIDATION RESULTS
============================================================
VALID FILES: 3,386
INVALID FILES: 0
============================================================
REFERENCE SCHEMA
============================================================
000 solution_id int64
001 designation string
002 source_id int64
003 random_index int64
004 ref_epoch double
005 ra double
006 ra_error float
007 dec double
008 dec_error float
009 parallax double
010 parallax_error float
011 parallax_over_error float
012 pm float
013 pmra double
014 pmra_error float
015 pmdec double
016 pmdec_error float
017 ra_dec_corr float
018 ra_parallax_corr float
019 ra_pmra_corr float
020 ra_pmdec_corr float
021 dec_parallax_corr float
022 dec_pmra_corr float
023 dec_pmdec_corr float
024 parallax_pmra_corr float
025 parallax_pmdec_corr float
026 pmra_pmdec_corr float
027 astrometric_n_obs_al int16
028 astrometric_n_obs_ac int16
029 astrometric_n_good_obs_al int16
030 astrometric_n_bad_obs_al int16
031 astrometric_gof_al float
032 astrometric_chi2_al float
033 astrometric_excess_noise float
034 astrometric_excess_noise_sig float
035 astrometric_params_solved int8
036 astrometric_primary_flag bool
037 nu_eff_used_in_astrometry float
038 pseudocolour float
039 pseudocolour_error float
040 ra_pseudocolour_corr float
041 dec_pseudocolour_corr float
042 parallax_pseudocolour_corr float
043 pmra_pseudocolour_corr float
044 pmdec_pseudocolour_corr float
045 astrometric_matched_transits int16
046 visibility_periods_used int16
047 astrometric_sigma5d_max float
048 matched_transits int16
049 new_matched_transits int16
050 matched_transits_removed int16
051 ipd_gof_harmonic_amplitude float
052 ipd_gof_harmonic_phase float
053 ipd_frac_multi_peak int8
054 ipd_frac_odd_win int8
055 ruwe float
056 scan_direction_strength_k1 float
057 scan_direction_strength_k2 float
058 scan_direction_strength_k3 float
059 scan_direction_strength_k4 float
060 scan_direction_mean_k1 float
061 scan_direction_mean_k2 float
062 scan_direction_mean_k3 float
063 scan_direction_mean_k4 float
064 duplicated_source bool
065 phot_g_n_obs int16
066 phot_g_mean_flux double
067 phot_g_mean_flux_error float
068 phot_g_mean_flux_over_error float
069 phot_g_mean_mag float
070 phot_bp_n_obs int16
071 phot_bp_mean_flux double
072 phot_bp_mean_flux_error float
073 phot_bp_mean_flux_over_error float
074 phot_bp_mean_mag float
075 phot_rp_n_obs int16
076 phot_rp_mean_flux double
077 phot_rp_mean_flux_error float
078 phot_rp_mean_flux_over_error float
079 phot_rp_mean_mag float
080 phot_bp_rp_excess_factor float
081 phot_bp_n_contaminated_transits int16
082 phot_bp_n_blended_transits int16
083 phot_rp_n_contaminated_transits int16
084 phot_rp_n_blended_transits int16
085 phot_proc_mode int8
086 bp_rp float
087 bp_g float
088 g_rp float
089 radial_velocity float
090 radial_velocity_error float
091 rv_method_used int8
092 rv_nb_transits int16
093 rv_nb_deblended_transits int16
094 rv_visibility_periods_used int16
095 rv_expected_sig_to_noise float
096 rv_renormalised_gof float
097 rv_chisq_pvalue float
098 rv_time_duration float
099 rv_amplitude_robust float
100 rv_template_teff float
101 rv_template_logg float
102 rv_template_fe_h float
103 rv_atm_param_origin int16
104 vbroad float
105 vbroad_error float
106 vbroad_nb_transits int16
107 grvs_mag float
108 grvs_mag_error float
109 grvs_mag_nb_transits int16
110 rvs_spec_sig_to_noise float
111 phot_variable_flag string
112 l double
113 b double
114 ecl_lon double
115 ecl_lat double
116 in_qso_candidates bool
117 in_galaxy_candidates bool
118 non_single_star int16
119 has_xp_continuous bool
120 has_xp_sampled bool
121 has_rvs bool
122 has_epoch_photometry bool
123 has_epoch_rv bool
124 has_mcmc_gspphot bool
125 has_mcmc_msc bool
126 in_andromeda_survey bool
127 classprob_dsc_combmod_quasar float
128 classprob_dsc_combmod_galaxy float
129 classprob_dsc_combmod_star float
130 teff_gspphot float
131 teff_gspphot_lower float
132 teff_gspphot_upper float
133 logg_gspphot float
134 logg_gspphot_lower float
135 logg_gspphot_upper float
136 mh_gspphot float
137 mh_gspphot_lower float
138 mh_gspphot_upper float
139 distance_gspphot float
140 distance_gspphot_lower float
141 distance_gspphot_upper float
142 azero_gspphot float
143 azero_gspphot_lower float
144 azero_gspphot_upper float
145 ag_gspphot float
146 ag_gspphot_lower float
147 ag_gspphot_upper float
148 ebpminrp_gspphot float
149 ebpminrp_gspphot_lower float
150 ebpminrp_gspphot_upper float
151 libname_gspphot string
============================================================
DONE
============================================================
Wizualizacje Drogi Mlecznej
Podstawowe wizualizacje były wykonywane w:
- Matplotlib
- Plotly
1. Czarno biały obraz nieba
Mapa jasności Drogi Mlecznej.
Widoczny:
- płaszczyzna galaktyki
- centralne zgrubienie galaktyki
- ciemne pasma pyłu międzygwiazdowego
- Wielki Obłok Magellana
- Mały Obłok Magellana

2. Obraz z naturalnymi kolorami z sensorów.
Naturalne kolory gwiazd na podstawie indeksu:
- BP – RP
Wizualizacja pokazuje:
- niebieskie młode gwiazdy (widoczne wyraźnie w obłokach Magellana)
- czerwone chłodne gwiazdy
- pył międzygwiazdowy
- strukturę dysku galaktycznego

3. Wizualizacja fałszywymi kolorami.
Sztuczne kolory dla lepszego podkreślenia struktur.
Pozwala lepiej zobaczyć:
- zagęszczenia gwiazd
- gradienty
- obłoki pyłu

Large Magellanic Cloud (LMC)
Selekcja gwiazd dla LMC
Najpierw zostały wybrane gwiazdy znajdujące się w obszarze Large Magellanic Cloud.
Filtr współrzędnych:
WHERE
l BETWEEN 265 AND 295
AND
b BETWEEN -45 AND -20
Dodatkowo zastosowano filtry jakości:
- brak nulli
- limit jasności
- poprawne proper motion
- ograniczenie paralaksy
Przykład:
phot_g_mean_mag < 20
AND parallax < 0.3
Sampling danych
Do renderowania używany był sampling:
MAX_POINTS = 1_500_000
Pozwalało to skrócić obliczenia oraz zachować strukturę LMC przy zachowaniu płynności wykresu.
W finalnym renderze zostało załadowanych:
- 8252 gwiazd
Lokalny układ współrzędnych
Współrzędne zostały przeliczone względem środka LMC:
LMC_L = 280.47
LMC_B = -32.89
Następnie utworzono lokalny układ:
x = (df["l"] - LMC_L)
y = (df["b"] - LMC_B)
Dzięki temu wykres był wycentrowany na obłoku Magellana.
Proper Motion i rekonstrukcja 3D
Do stworzenia pseudo-głębi wykorzystane zostały:
- pozycje gwiazd
- proper motion RA
- proper motion DEC
Następnie zastosowano PCA:
pca = PCA(n_components=3)
components = pca.fit_transform(
motion_features
)
Trzeci komponent PCA został użyty jako:
- pseudo depth
- kinematic depth
czyli przybliżona głębokość struktury LMC.
Podstawowe wizualizacje są równocześnie optyczną walidacją datasetu.
Format danych
Finalny dataset został zapisany jako:
- Apache Parquet
- kompresja ZSTD
- partycjonowane pliki (optymalny rozmiar około 200 MB)
To pozwala na:
- szybkie filtrowanie
- pracę z DuckDB
- pracę z Polars
- analizę bez ładowania całego datasetu do RAM
Wydajność ściągania
SQL ESA
- ~500 mln rekordów
- około 3 dni
- tylko wybrane kolumny
CDN ESA
- pełne Gaia DR3
- wszystkie rekordy
- wszystkie parametry
- około 3 dni
CDN okazał się zdecydowanie lepszym rozwiązaniem dla pełnego mirroru Gaia DR3. Gaia TAP SQL natomiast jest opcją dla użytkowników bez stacji roboczych do wybiórczego ściągania danych do analizy.
Wnioski
- Parquet + Polars + DuckDB daje ogromną wydajność
- Gaia DR3 można trzymać lokalnie
- walidacja MD5 jest konieczna przy ściąganiu za pomocą crawlera z cdn
- CDN ESA jest dużo szybszy od TAP SQL przy ściąganiu dużej ilości danych
- Plotly i matplotlib jest wystarczający do podstawowych interaktywnych map nieba
- sampling jest konieczny przy miliardach rekordów
Następne kroki
Możliwe dalsze rozwinięcia:
- 3D mapa Drogi Mlecznej
- mapa pyłu galaktycznego
- clustering gwiazd (UMAP)
- spiral arm reconstruction
- Wykresy HR

Dodaj komentarz