/hats-publish
설문조사 카탈로그 릴리스를 HATS 컬렉션(카탈로그 + 마진 + 인덱스 테이블)으로 변환합니다. 이 컬렉션은 소스 파일에 대해 검증되고, 문서화되며, 호스팅되고 등록됩니다. 이 절차는 hats-import 및 lsdb 문서, Rubin import 파이프라인(https://github.com/lincc-frameworks/rubin-dash) 및 공개 이슈와 아카이브된 import 노트북에 기록된 팀의 규칙을 코드화합니다. 모든 사이트별 값은 CONFIG.md에 설명된 사이트 파일에서 가져오며, 모든 참조는 공개 URL이며, 여기에는 기계, 사람 또는 데이터셋 이름이 명시되지 않습니다.
한 번의 실행 = 하나의 catalog.toml (templates/catalog.toml에서 작업 디렉토리로 복사됨). 모든 템플릿은 이 파일을 읽고, 그 안의 상대 경로는 파일이 있는 디렉토리를 기준으로 해석되며, 실행은 해당 파일만으로 재현 가능합니다. 작업 디렉토리를 유지하십시오. 설정, 로그, 실행된 검증 노트북 및 실행 로그가 보관됩니다.
각 실행 시작 시 템플릿을 고정합니다: T=$(bash <skill>/templates/pin_templates.sh) (작업 디렉토리에서)는 템플릿을 git 커밋과 함께 읽기 전용으로 templates.pinned/에 복사하며, 이후 모든 단계(job.sbatch 및 resubmit_loop.sh 포함)는 $T/...를 실행합니다. 그러면 git pull 또는 스킬 편집이 실행 중인 import를 변경할 수 없으며, README는 카탈로그를 구축한 커밋을 명시합니다. 실행 코드는 pin_templates.sh --repin으로만 변경하십시오.
사용 시기
게시할 새로운 설문조사 릴리스; 더 나은 파티셔닝, 작성자 설정 또는 메타데이터로 기존 HATS 카탈로그 재가져오기; HATS 복사본이 소스와 일치하는지 확인 요청.
입력 (설정되지 않은 경우에만 질문)
소스 파일 또는 URL 및 해당 형식; 설문조사, 릴리스, 데이터 모델 페이지, 논문, 승인 및 라이선스; HATS 버전이 이미 존재하는지 여부(data.lsdb.io data/ 트리 및 imports/README.md 확인); 좌표 및 ID 열. 그 외 모든 사항은 아래 인터뷰에서 결정됩니다.
절차
순서대로 진행되는 단계. 굵게 표시된 단계는 중단되고 사용자를 기다립니다. 각 단계는 실행 로그 항목(run_log.py start|end <phase>)으로 시작하고 끝납니다. 템플릿이 실행되는 곳에서 이를 자체적으로 수행합니다.
- 환경. 최신 릴리스된
hats,lsdb,hats-import(pip install -U hats lsdb hats-import nested-pandas pyarrow astropy fitsio jupyter)로 환경을 생성하거나 업데이트하고, 버전을 출력하며, 릴리스 노트에서 형식 변경 사항을 훑어봅니다.HATS_PUBLISH_SITE_ENV를 사이트 파일(CONFIG.md)로 지정합니다. 라이브러리를 사용하는 템플릿은 최소 버전 미만에서 실행을 거부하고, 최신 릴리스가 존재할 때 경고합니다. - 의사 결정 인터뷰 (
reference/decisions.md): 9개 그룹, 한 번에 몇 가지 질문, 각각 권장 기본값과 결과가 있습니다. 답변을catalog.toml및 실행 로그(run_log.py decision)에 기록합니다. 그런 다음 계획을 보여줍니다: 경로, 리더, 리소스, 파티셔닝, 작성자 설정, 이름, 대상. - 데이터 획득. 원시 디렉토리에 다운로드하고, 체크섬과 아카이브 무결성을 확인하며(
gzip -t), 모든 파일의 sha256을[source].sha256에 기록하고, 데이터 모델 페이지를 데이터 옆에 저장합니다. 파일 수를 아카이브 목록([source].expected_files)과 비교하고, 다시 다운로드된 복사본이 있을 수 있는 디렉토리에 대해 단순한 글로브(glob) 대신 정확한 파일 이름을 나열합니다. 수천 개의 작은 파일의 경우 인덱싱된 리더를 위한 인덱스 파일을 작성합니다. 백그라운드에서 실행 중인 다운로드는 작업 디렉토리에download.pid에 pid를 기록하여status.sh가 보고할 수 있도록 합니다. 2a. 좌표가 없는 테이블 ([source.positions_from]):attach_positions.py는 참조 HATS 컬렉션(해당 인덱스 테이블)에서 id로 위치를 조회하고ra/dec가 포함된 Parquet으로 소스를 작성합니다. 그러면 import가 해당 파일을 읽습니다. 배열 열이 있는 ECSV 헤더 CSV ([reader].ecsv_header = true)는 그 과정에서 목록 열로 구문 분석됩니다. 2b. 행-병렬 FITS 파일로 분할된 하나의 테이블 ([source.companions], 예: 동일한 행을 가진 메인 파일 + 추가/photo-z/light-curve 파일): import는 fitsio 행 범위로 나란히 읽고, 청크별로 키 열을 확인하며, 계산된 열([reader].derive, 작업 디렉토리의 함수)을 추가하고 목록 열을 하나의 중첩 열로 압축([reader].pack_nested)할 수 있습니다. 검증 로더는 동일한 파일을 독립적으로 읽습니다. - 파티셔닝 계획.
estimate_threshold.py --write는 실행의 작성자 설정으로 입력을 샘플링하고 200-800MB 파일 크기 규칙을pixel_threshold로 변환하며, 파티션 개수와dataset/_metadata크기를 예측합니다(4 GiB footer 제한 근처에서 경고).highest_order를 가장 밀도가 높은 영역에 대해 확인합니다. - 시험.
import_collection.py --trial-file <하나의 파일>을 시험 디렉토리로 실행합니다. dtypes, null 대 sentinels, 열 이름, 배열 열, 좌표가 없는 행([reader].drop_rows_without_coordinates는 드롭하고 개수를 셈)을 검사합니다.[reader],[columns],[properties]를 조정합니다. 사용자에게 변경된 사항을 표시합니다. - 가져오기.
import_collection.py를 분리하여(nohup/setsid), 또는 배치 노드에서job.sbatch로 (5-6단계 및 비교도 실행) 재개 가능하게 실행합니다. 이는[properties]및[writer]설정으로 카탈로그, 마진 및 인덱스 테이블을 구축합니다. 작은 테이블(약 1M 행 및 1GB 메모리 미만, 약 100k 행 이상의 넓은 테이블에서는 hats-import가 더 빠름)은 대신import_small.py를 사용합니다. 그런 다음write_ancillary.py: 데이터 썸네일(파티션당 무작위 샘플), 파티션별 통계, PNG 미리보기, README 및 출처 섹션이 있는index.html. 진행 상황:status.sh(작업 디렉토리에서)는 다운로드, SLURM 작업, 현재 hats-import 단계와 진행률 표시줄, 최신 실행 로그 항목을 출력합니다. 다운로드 및 가져오기는 몇 시간이 걸립니다. 백그라운드에서 실행(2단계 또는 5단계)되는 즉시 5분마다 업데이트를 시작합니다(묻지 않음). 각 업데이트는status.sh를 실행하고 변경된 사항만 보고합니다. 실행 중이며 사용자가 간격을 변경하거나 중지할 수 있다고 말합니다. 작업이 완료되거나 실패하면 업데이트를 중지하고, 작업이 큐를 떠날 때 실제 상태를 확인합니다. 선점 가능한 큐에서는 작업 옆에resubmit_loop.sh <job id>를 시작합니다. 작업의 리소스를resubmit_opts.txt에 기록하고, 선점되거나 시스템에 의해 취소된 작업을 동일한 리소스로 재제출합니다(hats-import는 재개됨; import가 완료된 후(import.done으로 표시) 선점된 작업은 import를 건너뛰고 재제출됨). 다른 경우에는 중지합니다. 5a. 중첩 시계열 제품 ([nested], 선택 사항):attach_nested.py는 참조 HATS에서 id별로 객체별 목록 열을 조인(공간 내부 조인)하고,nest_lists로 하나의 중첩 열로 압축하여 플랫 컬렉션 옆에 두 번째 컬렉션을 씁니다. 노트북의 섹션 9b는 행, 목록 길이 및 배열 샘플을 조정합니다. - 검증. 실패 시 실행 중단 (
reference/verification.md):verify_structure.py --spot-check(hats-import 검사, HATS-note 준수, 인코딩 스윕) →run_verify.sh(소스에 대한 값 수준 노트북; 검사는 PASS, FAIL 또는 SKIP을 이유와 함께 종료) → 사용자와 함께 검토 체크리스트. - 문서화 및 보관. data.lsdb.io
imports/디렉토리에catalog.toml, 사용된 스크립트 및 실행된 노트북을 추가하고, 해당 README 상단에 행을 추가합니다(사이트 풀 리퀘스트의 일부). - 호스팅 (
reference/publishing.md).publish_web.sh --check및publish_mirror.sh --check를 실행하고 미리보기(복사될 내용과 대상이 이미 보유한 내용)를 표시한 후, 사용자의 승인을 받은 후에만--yes로 실행합니다(두 플래그 중 하나가 없으면 중지됨; 빌드에 없는 파일을 대상이 보유하고 있으면--replace가 제공되지 않는 한 쓰기 전에 중지됨.--replace는 오래된 파일을 삭제함): 복사, 그룹화, 체크섬 매니페스트, 테이블별hats_status및hats_service_url, 웹 호스트의 심볼릭 링크, 컬렉션 루트에서lsdb.open_catalog를 사용한 공개 열기 테스트(실패 시 심볼릭 링크 되돌림), 그런 다음 autoindex 설명; 미러 복사본은verify_results_mirror.csv로 재검증됩니다. - 등록.
make_site_entry.py는 data.lsdb.io 클론의 브랜치에 페이지 항목과 밀도 맵을 쓰고(기존 항목에 병합) 스테이징합니다. 커밋 메시지를 요청합니다. 풀 리퀘스트는 사용자의 것입니다. 병합 및 배포 후,registry_entry.py는 사용자의 풀 리퀘스트를 위해 레지스트리 클론의 브랜치에서 레지스트리 생성기를 실행합니다.origin/main의 깨끗한 사이트 클론이 필요합니다. - 마무리. 템플릿의
NOTES.md; 열린 항목(미러, 레지스트리, 배포, 이전 버전 폐기);run_log.py feedback(사용자에게 무엇이 명확하지 않았고, 수동이었으며, 기본값에서 잘못되었는지);run_log.py render --scrub및 이 저장소의runlogs/에 로그를 추가하는 풀 리퀘스트 제안.
재가져오기: 새 임계값 또는 정렬을 위한 ImportArguments.reimport_from_hats, 마진 및 인덱스 재구축, 새 디렉토리에 쓰기, 검증, compare_versions.py --new <new> --old <previous> --key <id> 실행(공유 영역의 스키마, 행 및 값; 유형 축소는 별도로 보고됨), 심볼릭 링크 재지정, 페이지와 레지스트리가 새 링크를 가리킬 때까지 이전 복사본 유지.
템플릿
| 파일 | 목적 |
|---|---|
catalog.toml | 실행 구성 (복사 및 채우기) |
pin_templates.sh | 한 번 실행을 위해 templates.pinned/에 템플릿 고정 (커밋, 로컬 diff, 체크섬); 변경하려면 --repin |
_common.py, catalog_source.py, readers.py | 공유 헬퍼: 설정, 버전, 사이트 변수, 작성자 설정, 속성, 소스 로더, 좌표 필터 |
estimate_threshold.py | 파일 크기 규칙 → pixel_threshold |
import_collection.py | hats-import 컬렉션 빌드 (--dry-run, --trial-file) |
import_small.py | 작은 테이블을 위한 인메모리 경로 |
attach_positions.py | 좌표가 없는 테이블을 위해 참조 HATS에서 id로 위치; ECSV 배열이 목록 열로 구문 분석됨 |
attach_nested.py | 중첩 시계열 제품: 참조 HATS에서 id로 목록 열 조인, nest_lists, 컬렉션 쓰기 |
job.sbatch | 배치 경로: 전용 노드에서 하나의 SLURM 작업으로 import, 보조 파일, 검증 및 비교 |
write_ancillary.py | 썸네일, 통계, 미리보기, README, index.html |
verify_structure.py | 구조적, 준수 및 인코딩 검사 |
build_verify_notebook.py, run_verify.sh | 값 수준 검증 노트북 |
compare_versions.py | 새 빌드를 기존 HATS 버전과 비교 (재가져오기, 게시된 복사본에 대한 검증) |
publish_mirror.sh, publish_web.sh | 호스팅 대상 |
make_site_entry.py, registry_entry.py | data.lsdb.io 페이지 및 레지스트리 |
memwatch.sh | 공유 노드에서 긴 단일 프로세스 단계를 위한 메모리 감시 |
status.sh | 예약된 업데이트를 위한 한 화면 진행 상황 요약 (다운로드, 작업, import 단계, 실행 로그) |
resubmit_loop.sh | 선점 또는 시스템 취소 후 배치 작업 재제출; 실행당 하나의 루프 (하트비트 가드) |
run_log.py, NOTES.template.md | 실행 로그 및 노트 |
주의사항
각각 한 줄씩; 자세한 내용은 reference/pitfalls.md.
- 입력 파일당 하나의 Dask 태스크: 거대한 파일은 분할, 수천 개의 작은 파일에는 인덱싱된 리더 사용.
- 좌표가 없는 행은 매핑 단계를 중단시킴: 먼저 시험 가져오기, 필터링 및 개수 세기.
- Gzip 압축 CSV 입력은
compression="gzip"필요 (리더는 열린 핸들을 얻음); import가.gz파일에 대해 추가함. expected_total_rows가 일치해야 하며, 그렇지 않으면 파이프라인이 비닝 후 중지됨; 힌트가 아닌 검사임.- hats Parquet 기본값 사용 (hats, hats-import, lsdb >= 0.11.1): ZSTD 15, 페이지 인덱스, float 열에 BYTE_STREAM_SPLIT. 사용자가 달리 결정하지 않는 한
[writer]를 비워 둠; 스킬이 자체적으로 쓰는 파일은parquet_write_kwargs로 작성. 이전 버전은 float를 사전 인코딩하여 약 1.4배 더 큼. - 기본 열은 스키마에 존재해야 함; 중첩 열은
frame.subcol사용. - hats는
hats.properties및properties를 씀; 둘 다 편집하거나 둘 다 편집하지 않음. hats_release_date는 HATS 노트의 날짜이지 데이터의 날짜가 아님; 데이터 날짜는t_min/t_max에 넣음.- 마진은 추가 행을 보유할 수 있으며, 더 적은 행은 절대 안 됨: 포함으로 검증.
- 마진과 인덱스는
hats_primary_table_url에 빌드 경로를 전달함; 게시 스크립트가 상대 경로로 만듦. - 루트에서 컬렉션을 염; 페이지는 컬렉션 루트를 가리켜야 함.
- 웹
.htaccess는 첫 번째 일치 및 접두사 일치; 게시 스크립트는 일반 항목 앞에 삽입하고 이름 변경이 아닌 복사로 씀 (고정 디렉토리). - 열이 지역별로 다른 입력은 축소 과정에서 열을 조용히 잃음: 하나의 스키마로 통일 (
[reader].conform_schema, 모든 형식), 각 지역 시험. _metadata는 4 GiB를 초과할 수 없음:estimate_threshold.py가 예측; 거대한 카탈로그의 경우create_metadata = false.- Null 고정 크기 목록은 pyarrow < 26 리더를 깨뜨림: NaN으로 채우거나 가변 길이 목록 사용.
- 헤드리스 노트북의 진행률 표시줄은 죽은 위젯이 됨; 노트북 빌더는 텍스트 막대를 사용함.
- 병렬 셸은 하나의 작업 디렉토리를 공유함: 절대 경로,
pgrep -f대신 pid 파일 사용.
출력
호스팅 대상의 검증된 HATS 컬렉션, 스테이징된 data.lsdb.io 페이지, 레지스트리 브랜치, NOTES.md, verify_results.csv, 실행된 검증 노트북 및 RUNLOG.md.