Skip to content

Latest commit

ย 

History

History
387 lines (279 loc) ยท 19.3 KB

File metadata and controls

387 lines (279 loc) ยท 19.3 KB

FTP Batch Pipeline

๊ณผ์ œ ์„ ์ • ๋ฐฐ๊ฒฝ

EUV ์„ค๋น„ ๋‚ด๋ถ€ ์˜ค์—ผ์ด ํ™•์‚ฐ๋˜๋ฉด particle์ด reticle ๋˜๋Š” reticle stage(RS)์— ์œ ์ž…๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด reticle์„ scanner์— loadingํ•˜๊ธฐ ์ „ ์ˆ˜ํ–‰ํ•˜๋Š” RBI(Reticle Backside Inspection) ๊ฒ€์‚ฌ์—์„œ fail์ด ๋ฐœ์ƒํ•˜๊ณ , reticle loading์ด ์ง„ํ–‰๋˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ reticle backside ์˜ค์—ผ๊ณผ ๊ด€๋ จ๋œ ๊ฒ€์‚ฌ ํ…์ŠคํŠธ ๋ฐ ์ด๋ฏธ์ง€๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ˆ˜์ง‘ํ•˜๊ณ , ๋ฐœ์ƒ ์‹œ์  ๊ธฐ์ค€์œผ๋กœ ์—ฐ๊ฒฐํ•ด ๋ถ„์„ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ณผ์ œ ๋ชฉํ‘œ

RUBI ํ…์ŠคํŠธ์™€ RUIP ์ด๋ฏธ์ง€๋ฅผ ์ˆ˜์ง‘ ๋ฐ ๋งค์นญํ•˜์—ฌ reticle backside ์˜ค์—ผ ๋ถ„์„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ RBI fail ์›์ธ particle์˜ ๋ฐœ์ƒ ์‹œ์ ๊ณผ ๊ด€๋ จ ์ด๋ฏธ์ง€๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ…์ŠคํŠธ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ์™€ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ 1:1๋กœ ์—ฐ๊ฒฐํ•˜๊ณ , ๋ณ€ํ™˜๋œ PNG ๊ฒฐ๊ณผ๋ฌผ์„ ๋ถ„์„ ์„œ๋ฒ„ ๊ฒฝ๋กœ์— ์—…๋กœ๋“œํ•˜๋Š” ๋ฐฐ์น˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ์„ ํƒ์ง€ ๋ฐ ์„ ํƒ ์‚ฌ์œ 

๋ณธ ์‹œ์Šคํ…œ์€ reticle ์˜ค์—ผ ์›์ธ ๋ถ„์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ, ๋ถ„์„์— ํ•„์š”ํ•œ ๊ฒ€์‚ฌ ํ…์ŠคํŠธ์™€ ์ด๋ฏธ์ง€ evidence๋ฅผ ์ •ํ•ฉ์„ฑ ์žˆ๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ์ดํ„ฐ ํŒŒ์ดํ”„๋ผ์ธ์ž…๋‹ˆ๋‹ค. ๊ตฌํ˜„ ์‹œ ์„ ํƒํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ์ฃผ์š” ๊ธฐ์ˆ ์  ๋ถ„๊ธฐ์ ๊ณผ ํ˜„์žฌ ์„ ํƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ถ„๊ธฐ์  ์„ ํƒ ๊ฐ€๋Šฅ ๋ฐฉ์‹ ํ˜„์žฌ ์„ ํƒ ์„ ํƒ ์‚ฌ์œ 
์ฒ˜๋ฆฌ ๊ธฐ์ค€ ์ด๋ฏธ์ง€ ๊ธฐ์ค€, ํ…์ŠคํŠธ ๊ธฐ์ค€, ํ…์ŠคํŠธ+์ด๋ฏธ์ง€ ํ†ตํ•ฉ ์ฒ˜๋ฆฌ COMBINED ํ…์ŠคํŠธ ๊ธฐ์ค€ ํ†ตํ•ฉ ์ฒ˜๋ฆฌ RBI ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ ํ…์ŠคํŠธ๊ฐ€ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ์ด๊ณ , ์ด๋ฏธ์ง€๋Š” ๋ถ„์„ ๊ทผ๊ฑฐ ์ž๋ฃŒ๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
๋งค์นญ ๋ฐฉ์‹ ํŒŒ์ผ๋ช… ๊ธฐ์ค€, ์‹œ๊ฐ„ ๊ธฐ์ค€, reticle ID/๊ฒ€์‚ฌ ID ๊ธฐ์ค€, ์ˆ˜๋™ ๋งค์นญ ํŒŒ์ผ๋ช… prefix์™€ timestamp ๊ธฐ๋ฐ˜ ์ž๋™ ๋งค์นญ ํ˜„์žฌ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์—์„œ ๊ณตํ†ต์œผ๋กœ ํ™•๋ณด ๊ฐ€๋Šฅํ•œ ์‹๋ณ„์ž๊ฐ€ ํŒŒ์ผ๋ช… prefix์™€ ์ƒ์„ฑ ์‹œ๊ฐ์ž…๋‹ˆ๋‹ค.
๋งค์นญ ์‹œ๊ฐ„ ๋ฒ”์œ„ ๋™์ผ ์‹œ๊ฐ๋งŒ ํ—ˆ์šฉ, 1๋ถ„ ์ด๋‚ด, 5๋ถ„ ์ด๋‚ด, 10๋ถ„ ์ด์ƒ, ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํŒŒ์ผ ๋ฌด์กฐ๊ฑด ๋งค์นญ 5๋ถ„ ์ด๋‚ด ์ตœ๊ทผ์ ‘ ์ด๋ฏธ์ง€ 1๊ฐœ ๋„ˆ๋ฌด ์ข์œผ๋ฉด ์ •์ƒ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ˆ„๋ฝ๋˜๊ณ , ๋„ˆ๋ฌด ๋„“์œผ๋ฉด ์ž˜๋ชป๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ์–ด 5๋ถ„์„ ๊ธฐ์ค€์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค.
๋งค์นญ ์‹คํŒจ ์ฒ˜๋ฆฌ ์ „์ฒด skip, ํ…์ŠคํŠธ๋งŒ ์ €์žฅ, ๋ฏธ๋งค์นญ ์ƒํƒœ ์ €์žฅ, ์—๋Ÿฌ ํ›„ ์žฌ์‹œ๋„ COMBINED์—์„œ๋Š” ํ…์ŠคํŠธ๋งŒ ์ €์žฅ ํ…์ŠคํŠธ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๋Š” ๋ถ„์„์˜ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ ์ด๋ฏธ์ง€๊ฐ€ ์—†์–ด๋„ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค.
์ค‘๋ณต ์ฒ˜๋ฆฌ ๋งค๋ฒˆ ๋ณ€ํ™˜/์—…๋กœ๋“œ, ๊ธฐ์กด ๊ฒฐ๊ณผ skip, ํ•ด์‹œ ๋น„๊ต, DB ์ƒํƒœ๊ฐ’ ๊ธฐ์ค€ ์žฌ์ฒ˜๋ฆฌ ์„œ๋ฒ„ PNG ์กด์žฌ ์‹œ skip, ๋กœ์ปฌ PNG ์กด์žฌ ์‹œ ์žฌ์‚ฌ์šฉ ๋ฐ˜๋ณต ์‹คํ–‰ ์‹œ ๋ถˆํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ๋ณ€ํ™˜๊ณผ ์—…๋กœ๋“œ ๋น„์šฉ์„ ์ค„์ž…๋‹ˆ๋‹ค.
์™„๋ฃŒ ๊ธฐ์ค€ DB ์ €์žฅ ์„ฑ๊ณต, PNG ๋ณ€ํ™˜ ์„ฑ๊ณต, ์„œ๋ฒ„ ์—…๋กœ๋“œ ์„ฑ๊ณต, ์›๋ณธ ์‚ญ์ œ ์„ฑ๊ณต ์„œ๋ฒ„ ์—…๋กœ๋“œ ์„ฑ๊ณต ํ›„ DB ์ €์žฅ ๋ฐ ์›๋ณธ ์‚ญ์ œ ๋ถ„์„ ์„œ๋ฒ„์— ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ์™„๋ฃŒ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ์ค„์ž…๋‹ˆ๋‹ค.
์›๋ณธ ํŒŒ์ผ ์ฒ˜๋ฆฌ ์›๋ณธ ์œ ์ง€, ์„ฑ๊ณต ํ›„ ์‚ญ์ œ, archive ์ด๋™, ์‹คํŒจ ํŒŒ์ผ ๋ณ„๋„ ๋ณด๊ด€ ์ฒ˜๋ฆฌ ์„ฑ๊ณต ํ›„ FTP ์›๋ณธ ์‚ญ์ œ ์ค‘๋ณต ์ฒ˜๋ฆฌ๋ฅผ ์ค„์ด๊ณ  ์ž…๋ ฅ ๊ฒฝ๋กœ๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
๋‚ ์งœ ๋ฒ”์œ„ ์ž…๋ ฅ์ผ๋งŒ ์ฒ˜๋ฆฌ, ์ „๋‚ +์ž…๋ ฅ์ผ ์ฒ˜๋ฆฌ, ์ „ํ›„ N์ผ ์ฒ˜๋ฆฌ, ๋งˆ์ง€๋ง‰ ์ฒ˜๋ฆฌ ์‹œ์  ์ดํ›„ ์ฒ˜๋ฆฌ ์ „๋‚ +์ž…๋ ฅ์ผ 2์ผ ์ฒ˜๋ฆฌ ์ž์ • ์ „ํ›„์— ์ƒ์„ฑ๋œ ํ…์ŠคํŠธ์™€ ์ด๋ฏธ์ง€์˜ ๋งค์นญ ๋ˆ„๋ฝ์„ ์ค„์ž…๋‹ˆ๋‹ค.

๊ฐœ์š”

์ด ํ”„๋กœ์ ํŠธ๋Š” FTP ์„œ๋ฒ„์˜ RUBI ํ…์ŠคํŠธ์™€ RUIP ์ด๋ฏธ์ง€๋ฅผ ์ˆ˜์ง‘ํ•ด ์ฒ˜๋ฆฌํ•˜๋Š” reticle ์˜ค์—ผ ๋ถ„์„์šฉ ๋ฐฐ์น˜์ž…๋‹ˆ๋‹ค.

  • RUBI: ํ…์ŠคํŠธ ํŒŒ์ผ์„ ํŒŒ์‹ฑํ•ด SQLite์— ๋ฒŒํฌ ์ธ์„œํŠธํ•ฉ๋‹ˆ๋‹ค.
  • RUPI: ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ๋ฅผ ๋งค์นญํ•ด PNG๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  FTP rbi/ruip/.../*.png๋กœ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  • COMBINED: ํ…์ŠคํŠธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ด๋ฏธ์ง€๊นŒ์ง€ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•˜๋Š” ํ†ตํ•ฉ ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ์šด์˜ ๊ธฐ๋ณธ๊ฐ’์€ COMBINED ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค. ์ž…๋ ฅ์ผ ํ•˜๋‚˜๋ฅผ ๋ฐ›์œผ๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ์ „๋‚  + ์ž…๋ ฅ์ผ ๋‘ ๋‚ ์งœ๋ฅผ ํ•จ๊ป˜ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ER Dose Error ๋ฐฐ์น˜

ER_DOSE_RAW ๋ฐฐ์น˜๋Š” mbeat.er_data_raw์˜ dose warning ๋กœ๊ทธ๋ฅผ ํŒŒ์‹ฑํ•ด prism_common.er_dose_raw_parsed์— ์ ์žฌํ•˜๋ฉฐ, ์ˆ˜์ง‘ ์™„๋ฃŒ ํ›„ prism_common.de_trend_die_yield_daily ์ผ๋ณ„ DIE Yield ์„œ๋จธ๋ฆฌ ํ…Œ์ด๋ธ”์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค. parsed ํ…Œ์ด๋ธ”์—๋Š” eq_name, code, code_occur_time, title, contents์™€ contents์—์„œ ์‹ค์ œ๋กœ ํ•„์š”ํ•œ exposure_handle, action_handle, lot_id, lot_name, lot_seq, wafer_seq, de_err, n_slit, use_yn์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์กฐํšŒ ๋Œ€์ƒ code๋Š” DW-3411, DW-3425, DW-343A, DW-343B, LO-0050, LO-0051, LO-0052, LO-0061, LO-8166, LO-8167, KE-9103, KE-9104์ด๋ฉฐ, ์ฝ”๋“œ ๊ฐ’์€ DB์— ์ €์žฅ๋œ ์›๋ณธ ํ˜•์‹ ๊ทธ๋Œ€๋กœ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐ์น˜๋Š” code_occur_time ๊ธฐ๊ฐ„ ์กฐ๊ฑด์œผ๋กœ ์กฐํšŒํ•œ ํ›„๋ณด๋ฅผ ํ•œ ๋ฒˆ์— ๋ฉ”๋ชจ๋ฆฌ๋กœ ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ , chunk ๋‹จ์œ„๋กœ ์ฝ์–ด์„œ ํŒŒ์‹ฑ ํ›„ ๋ฐ”๋กœ COPY ์ ์žฌํ•ฉ๋‹ˆ๋‹ค. ํŒŒํ‹ฐ์…˜ ์ ์žฌ๋Š” ๊ณตํ†ต copy_insert_to_partition_table์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ ์žฌ ์ „์— DataFrame ์ปฌ๋Ÿผ์„ ํ…Œ์ด๋ธ”์˜ ๋ฌผ๋ฆฌ ์ปฌ๋Ÿผ ์ˆœ์„œ์™€ ๋™์ผํ•˜๊ฒŒ ์ •๋ ฌํ•œ ๋’ค COPY ... FROM STDIN WITH CSV HEADER๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ธฐ๋ณธ chunk ํฌ๊ธฐ๋Š” ER_DOSE_RAW ๋ฐ ER_DOSE_EUV ๋ฐฐ์น˜ ๋ชจ๋‘ 30000์ด๋ฉฐ ์‹คํ–‰ ์‹œ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์กฐํšŒ๋Š” SQLAlchemy ์„œ๋ฒ„์‚ฌ์ด๋“œ ์ปค์„œ(stream_results=True, max_row_buffer=chunk_size) ๊ธฐ๋ฐ˜ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ์ˆ˜ํ–‰๋˜์ง€๋งŒ, ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์€ chunk ํฌ๊ธฐ์™€ raw contents ํฌ๊ธฐ์— ์˜ํ–ฅ์„ ๋ฐ›์œผ๋ฏ€๋กœ ์šด์˜ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์กฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฒญํฌ ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌ๋˜๋”๋ผ๋„ ์„ค๋น„(eq_name)๋ณ„๋กœ ์ด์ „์— ํŒŒ์‹ฑํ•œ lot_seq์™€ wafer_seq๋ฅผ ๊ธฐ์–ตํ•˜์—ฌ ์ง€์† ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ER_DOSE_RAW์€ ์ ์žฌ worker 1๊ฐœ๋ฅผ ์‚ฌ์šฉํ•ด ์ด์ „ ์ฒญํฌ์˜ COPY์™€ ๋‹ค์Œ ์ฒญํฌ์˜ ์กฐํšŒยทํŒŒ์‹ฑ์„ ๊ฒน์ณ ์‹คํ–‰ํ•˜๋ฉฐ, ๋Œ€๊ธฐ ์ค‘์ธ DataFrame์€ ์ตœ๋Œ€ 1๊ฐœ๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€๊ฒฝ์˜ ์šด์˜ ์‹ค์ธก ๊ฒฐ๊ณผ๋Š” DB ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐ RAW ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฌธ์„œ์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

ER_DOSE_RAW์™€ ER_DOSE_EUV์˜ processor ๊ธฐ๋ณธ ์‹คํ–‰์€ ์ตœ๊ทผ 2์ผ lookback ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค. ์‹คํ–‰์ผ ๊ธฐ์ค€ ์˜ค๋Š˜ ํฌํ•จ ์ตœ๊ทผ 2์ผ์„ ๋‚ ์งœ๋ณ„๋กœ ๊ฒ€์‚ฌํ•˜๊ณ , ๋จผ์ € ์›์ฒœ raw์™€ parsed์˜ ์ „์ฒด ๊ฑด์ˆ˜๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฐฐ์น˜ ๋ชจ๋‘ ์ „์ฒด ๊ฑด์ˆ˜๊ฐ€ ๋‹ค๋ฅด๊ณ  parsed ๊ฑด์ˆ˜๊ฐ€ 0๋ณด๋‹ค ํด ๋•Œ๋งŒ ์›์ฒœ์—์„œ (eq_name, code, code_occur_time)์ด ๊ฐ™์€ ํ–‰์„ ์ค‘๋ณต ์ œ๊ฑฐํ•œ ๊ฑด์ˆ˜๋ฅผ ํ•œ ๋ฒˆ ๋” ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฑด์ˆ˜๊ฐ€ parsed ๊ฑด์ˆ˜์™€ ๊ฐ™์œผ๋ฉด ์ค‘๋ณต์œผ๋กœ ์ธํ•œ ์ฐจ์ด์ด๋ฏ€๋กœ ์Šคํ‚ตํ•˜๊ณ , ์—ฌ์ „ํžˆ ๋‹ค๋ฅด๊ฑฐ๋‚˜ parsed ๊ฑด์ˆ˜๊ฐ€ 0์ด๋ฉด ํ•ด๋‹น ๋‚ ์งœ parsed ํŒŒํ‹ฐ์…˜์„ TRUNCATEํ•œ ๋’ค ์›์ฒœ raw๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ํŒŒ์‹ฑํ•ด ์ ์žฌํ•ฉ๋‹ˆ๋‹ค. ER_DOSE_EUV_TARGET_DATE๋ฅผ ๋ช…์‹œํ•˜๋ฉด ํ•ด๋‹น ๋‚ ์งœ 1์ผ๋งŒ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ฒ€์‚ฌํ•˜๊ณ , ER_DOSE_START_TIME/ER_DOSE_END_TIME๋ฅผ ๋ช…์‹œํ•˜๋ฉด count ๋น„๊ต ์—†์ด ์ง€์ •ํ•œ ์‹œ๊ฐ„ ๋ฒ”์œ„๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. EUV source count๋Š” root cause ํŒŒ์‹ฑ ๋Œ€์ƒ์ธ contents๋งŒ ์„ธ์–ด parsed count์™€ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

DW ๋กœ๊ทธ์—์„œ exposure_handle์ด ๊ฐ™์€ ์„ค๋น„์˜ ์ด์ „ ๊ฐ’๋ณด๋‹ค 1000 ์ด์ƒ ์ปค์ง€๋ฉด ํ…Œ์ŠคํŠธ์ƒท์„ฑ row๋กœ ๋ณด๊ณ  ์ €์žฅ์€ ํ•˜๋˜ use_yn='N'์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ๋ถ„์„์—์„œ๋Š” use_yn='Y' ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , row ์ž์ฒด๋Š” ์ €์žฅ๋˜๋ฏ€๋กœ raw count์™€ parsed count ๋น„๊ต๊ฐ€ ๊ณ„์† ์–ด๊ธ‹๋‚˜๋Š” ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ER_DOSE_EUV๋Š” mbeat.er_data_raw_euv ๊ธฐ๋ฐ˜ root cause ๊ฒฐ๊ณผ์šฉ ์‹คํ–‰์ž…๋‹ˆ๋‹ค. ๋Œ€์ƒ ๊ฒฐ๊ณผ๋Š” prism_common.er_dose_euv_parsed์— ์ €์žฅํ•˜๋ฉฐ, er_line, belong, type์€ ์ €์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. contents์—์„œ dose_error_detected_in_file, exposure_id, time, root_cause์™€ ๊ฐ์ข… EUV metric ์ปฌ๋Ÿผ์„ ํŒŒ์‹ฑํ•ด ์ ์žฌํ•ฉ๋‹ˆ๋‹ค. ์ปฌ๋Ÿผ๋ช…์€ ์†Œ๋ฌธ์ž snake_case ๊ธฐ์ค€์œผ๋กœ ๊ณต๋ฐฑ, ., -, <, =๋ฅผ _๋กœ ์น˜ํ™˜ํ•˜๋ฉฐ, ํŒŒ์ƒ ์ปฌ๋Ÿผ์€ root_cause_code๋งŒ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์‹ฑ ๋ฐ ์ ์žฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด prism_common.de_trend_root_cause_daily ์„œ๋จธ๋ฆฌ ํ…Œ์ด๋ธ”์— ์ผ๋ณ„/์„ค๋น„๋ณ„/์›์ธ๋ณ„ ๋ฐœ์ƒ ๋นˆ๋„(frequency)๋ฅผ ์ž๋™ UPSERT ํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ธ ์Šคํ‚ค๋งˆ์™€ ํŒŒ์‹ฑ ๊ทœ์น™์€ ER_DOSE_ERROR.md๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

ftp_batch/
โ”œโ”€โ”€ app/
โ”‚   โ””โ”€โ”€ batch_runner.py
โ”œโ”€โ”€ common/
โ”‚   โ”œโ”€โ”€ date_utils.py
โ”‚   โ””โ”€โ”€ path_utils.py
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ local_test_settings.py
โ”œโ”€โ”€ infra/
โ”‚   โ”œโ”€โ”€ db_manager.py
โ”‚   โ””โ”€โ”€ ftp_scanner.py
โ”œโ”€โ”€ matching/
โ”‚   โ””โ”€โ”€ image_text_matcher.py
โ””โ”€โ”€ processors/
    โ”œโ”€โ”€ rubi_processor.py
    โ””โ”€โ”€ rupi_processor.py

batch_main/
โ””โ”€โ”€ main.py
airflow_modules/
โ””โ”€โ”€ ftp_batch_jobs.py
dags/
โ””โ”€โ”€ ftp_batch_hourly_dag.py

main.py
test.py
init_db.py
local_ftp_server.py
IMAGE_TEXT_MATCHING.md

์ฒ˜๋ฆฌ ํ๋ฆ„

RUBI

  1. /RUBI/<YYYYMMDD> ์Šค์บ”
  2. ํŒŒ์ผ๋ณ„ ๋‹ค์šด๋กœ๋“œ
  3. ํ…์ŠคํŠธ ํŒŒ์‹ฑ ํ›„ DataFrame ์ƒ์„ฑ
  4. SQLite ๋ฒŒํฌ ์ธ์„œํŠธ
  5. commit ์„ฑ๊ณต ์‹œ FTP ์›๋ณธ ์‚ญ์ œ

RUPI

  1. /RUIP/<YYYYMMDD> ์ด๋ฏธ์ง€ ์Šค์บ”
  2. /RUBI/<YYYYMMDD> ํ…์ŠคํŠธ ํ›„๋ณด ์กฐํšŒ
  3. ์ด๋ฏธ์ง€ ๊ธฐ์ค€์œผ๋กœ ๊ฐ€๊นŒ์šด ํ…์ŠคํŠธ ๋งค์นญ
  4. ๋กœ์ปฌ PNG ์ค€๋น„
  5. ๋งˆ์ง€๋ง‰์— ์—…๋กœ๋“œ ํ๋ฅผ ์ˆœ์ฐจ ์—…๋กœ๋“œ

COMBINED

  1. ์ „๋‚  + ์ž…๋ ฅ์ผ์˜ /RUBI์™€ /RUIP๋ฅผ ๋ชจ๋‘ ๋จผ์ € ๋‹ค์šด๋กœ๋“œ
  2. ํ…์ŠคํŠธ ํŒŒ์ผ์„ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ํŒŒ์‹ฑ
  3. ํ…์ŠคํŠธ๋ณด๋‹ค ๋Šฆ์ง€ ์•Š๊ณ  5๋ถ„ ์ด๋‚ด์ธ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ด๋ฏธ์ง€ 1๊ฐœ๋ฅผ 1:1 ๋งค์นญ
  4. ๋งค์นญ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด PNG ์ค€๋น„ ํ›„ ์—…๋กœ๋“œ ํ์— ๋“ฑ๋ก
  5. ๋งค์นญ ์—†๋Š” ํ…์ŠคํŠธ๋Š” ํ…์ŠคํŠธ๋งŒ DB ์ €์žฅ
  6. ๋งˆ์ง€๋ง‰ ์—…๋กœ๋“œ ๋‹จ๊ณ„์—์„œ ์„ฑ๊ณตํ•œ ํ•ญ๋ชฉ๋งŒ DB finalize ํ›„ ํ…์ŠคํŠธ/์ด๋ฏธ์ง€ FTP ์›๋ณธ ์‚ญ์ œ

์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

BatchRunner

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/app/batch_runner.py

  • RUBI, RUPI, COMBINED ์‹คํ–‰ ๋ถ„๊ธฐ
  • ์ „๋‚  + ์ž…๋ ฅ์ผ ๋‘ ๋‚ ์งœ ์ฒ˜๋ฆฌ
  • COMBINED์—์„œ ๋กœ์ปฌ PNG 3์ผ ๋ณด๊ด€ cleanup
  • ์—…๋กœ๋“œ ํ ์ œ์–ด

FTPScanner

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/infra/ftp_scanner.py

  • ๋‚ ์งœ ํด๋” ์Šค์บ”
  • ๋‹ค์šด๋กœ๋“œ/์—…๋กœ๋“œ
  • ์›๊ฒฉ ์กด์žฌ ์—ฌ๋ถ€์™€ ํฌ๊ธฐ ๊ฒ€์ฆ
  • FTP ์›๋ณธ ์‚ญ์ œ

ํ˜„์žฌ scan()์€ ๋‚ ์งœ ํด๋” ๋ฐ”๋กœ ์•„๋ž˜ ํŒŒ์ผ๋งŒ ์กฐํšŒํ•˜๊ณ  ์žฌ๊ท€ ์Šค์บ”์€ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

DBManager

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/infra/db_manager.py

  • select(query, params=None, connection=None)
  • bulk_insert_df(table_name, df, connection=None)
  • execute(query, params=None, connection=None)
  • transaction()

์กฐํšŒ๋Š” pandas.read_sql_query, ์ธ์„œํŠธ๋Š” DataFrame -> sqlite3.executemany ๊ธฐ๋ฐ˜ ๋ฒŒํฌ ์ธ์„œํŠธ์ž…๋‹ˆ๋‹ค.

RubiProcessor

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/processors/rubi_processor.py

  • ํ…์ŠคํŠธ ๋””์ฝ”๋”ฉ
  • ๋ผ์ธ ํŒŒ์‹ฑ
  • rubi_ingest์šฉ DataFrame ์ƒ์„ฑ

RupiProcessor

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/processors/rupi_processor.py

  • TIF -> PNG ๋ณ€ํ™˜
  • rupi_ingest upsert/finalize
  • ๋กœ์ปฌ PNG ๊ฒฝ๋กœ ์ƒ์„ฑ

image_text_matcher

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/matching/image_text_matcher.py

  • ํŒŒ์ผ๋ช…์—์„œ prefix, timestamp ์ถ”์ถœ
  • ํ…์ŠคํŠธ ๊ธฐ์ค€ ์ตœ๊ทผ์ ‘ ์ด๋ฏธ์ง€ ์„ ํƒ
  • ์ด๋ฏธ์ง€ ๊ธฐ์ค€ ์ตœ๊ทผ์ ‘ ํ…์ŠคํŠธ ์„ ํƒ
  • RUIP -> rbi/ruip/.../*.png ๊ฒฝ๋กœ ๋ณ€ํ™˜

์‹คํ–‰ ๋ฐฉ๋ฒ•

๊ณตํ†ต main ์‹คํ–‰

์šด์˜์šฉ ๊ณตํ†ต ์ง„์ž…์ ์€ main.py ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๋ถ„๊ธฐ ๋กœ์ง์€ batch_main/main.py์— ๋‘๊ณ , ๋ฃจํŠธ main.py๋Š” ์–‡์€ ์‹คํ–‰ ๋ž˜ํผ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

BATCH_TARGET ๊ฐ’์— ๋”ฐ๋ผ RBI ๋ฐฐ์น˜์™€ ER Dose ๋ฐฐ์น˜๋ฅผ ๋ถ„๊ธฐํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

cd /Users/parkjunho/PycharmProjects/PythonStudy

RBI ์‹คํ–‰:

BATCH_TARGET=RBI \
RBI_INPUT_DATE=2026-05-31 \
RBI_PARSER=COMBINED \
.venv/bin/python main.py

ER_DOSE_RAW ์‹คํ–‰:

ER_DOSE_DB_DSN='postgresql://user:password@host:5432/dbname' \
.venv/bin/python main.py --date 2026-05-31 --parser ER_DOSE_RAW

๋˜๋Š” er_dose.properties ์— DB ์—ฐ๊ฒฐ์„ ๋„ฃ๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ER_DOSE_DB_DSN=postgresql://user:password@host:5432/dbname

ER_DOSE_EUV๋„ ER_DOSE_RAW์™€ ๋ณ„๋„ ์‹คํ–‰์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

ํ•„์ˆ˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜:

  • BATCH_TARGET: RBI, ER_DOSE_RAW, ER_DOSE_EUV
  • RBI_INPUT_DATE: RBI ๊ธฐ์ค€ ๋‚ ์งœ, YYYY-MM-DD
  • ER_DOSE_DB_DSN ๋˜๋Š” DATABASE_URL: PostgreSQL DSN
  • ๋˜๋Š” ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ er_dose.properties ํŒŒ์ผ์˜ ER_DOSE_DB_DSN

์„ ํƒ ํ™˜๊ฒฝ๋ณ€์ˆ˜:

  • RBI_PARSER: RUBI, RUPI, COMBINED, ๊ธฐ๋ณธ๊ฐ’ COMBINED
  • ER_DOSE_RAW_TARGET_DATE: ER Dose raw ๋Œ€์ƒ ๋‚ ์งœ, YYYY-MM-DD
  • ER_DOSE_EUV_TARGET_DATE: ER Dose EUV ๋Œ€์ƒ ๋‚ ์งœ, YYYY-MM-DD
  • ER_DOSE_CHUNK_SIZE: ER Dose raw/euv fetch chunk ํฌ๊ธฐ
  • ER_DOSE_LOOKBACK_DAYS: ER_DOSE_RAW ๊ธฐ๋ณธ lookback ์ผ์ˆ˜, ๊ธฐ๋ณธ๊ฐ’ 2
  • INPUT_DATE: RBI_INPUT_DATE ๋Œ€์ฒด๊ฐ’
  • ER_DOSE_TARGET_DATE: raw ๋ ˆ๊ฑฐ์‹œ ๋Œ€์ƒ ๋‚ ์งœ ์ด๋ฆ„
  • TARGET_DATE: ER_DOSE_TARGET_DATE ๋ ˆ๊ฑฐ์‹œ ๋Œ€์ฒด๊ฐ’
  • START_TIME: ER_DOSE_START_TIME ๋Œ€์ฒด๊ฐ’
  • END_TIME: ER_DOSE_END_TIME ๋Œ€์ฒด๊ฐ’
  • ER_DOSE_START_TIME, ER_DOSE_END_TIME: ๊ธฐ์กด ์‹œ๊ฐ„ ๋ฒ”์œ„ ์ง์ ‘ ์ง€์ • ๋ฐฉ์‹๋„ ๊ณ„์† ์ง€์›. ๋‘ ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ ํ•จ๊ป˜ ์ง€์ •ํ•ด์•ผ ํ•จ

๋กœ์ปฌ ํŒจํ‚ค์ง€ ์„ค์น˜:

mkdir -p .vendor
pip3 install --target .vendor SQLAlchemy psycopg2-binary

sitecustomize.py ๊ฐ€ .vendor ๋ฅผ ์ž๋™์œผ๋กœ sys.path ์— ์ถ”๊ฐ€ํ•˜๋ฏ€๋กœ ๋ณ„๋„ PYTHONPATH ์„ค์ • ์—†์ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ ๊ทœ์น™:

  • main.py --date <YYYY-MM-DD> --parser RUBI|RUPI|COMBINED์ด๋ฉด FTP ๊ธฐ๋ฐ˜ RBI ๋ฐฐ์น˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • main.py --date <YYYY-MM-DD> --parser ER_DOSE_RAW์ด๋ฉด ํ•ด๋‹น ํ•˜๋ฃจ์˜ ER RAW ๋กœ๊ทธ ํŒŒ์‹ฑ ๋ฐฐ์น˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • main.py --date <YYYY-MM-DD> --parser ER_DOSE_EUV์ด๋ฉด EUV root cause ํŒŒ์‹ฑ ๋ฐฐ์น˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€์ ์œผ๋กœ ER_DOSE_RAW๋Š” ER_DOSE_RAW_TARGET_DATE, ER_DOSE_EUV๋Š” ER_DOSE_EUV_TARGET_DATE๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • raw/euv processor ๋ชจ๋‘ ๋Œ€์ƒ ๋‚ ์งœ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฃจ ๋ฒ”์œ„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
  • BATCH_TARGET=ER_DOSE_RAW๊ฐ€ ํ˜„์žฌ raw ๋ฐฐ์น˜์˜ ๊ธฐ๋ณธ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ๋ ˆ๊ฑฐ์‹œ ER_DOSE๋„ ๊ณ„์† ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  • BATCH_TARGET=ER_DOSE_RAW ๋˜๋Š” BATCH_TARGET=ER_DOSE_EUV๋ฅผ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋งŒ์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ  ๋‚ ์งœ ์ธ์ž๋ฅผ ์ฃผ์ง€ ์•Š์œผ๋ฉด ์ตœ๊ทผ 2์ผ lookback + ๋‚ ์งœ๋ณ„ count ๋น„๊ต ๊ธฐ๋ฐ˜ ์žฌ์ ์žฌ ์ „๋žต์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฐฐ์น˜ ๋ชจ๋‘ ์ „์ฒด count๊ฐ€ ๋‹ค๋ฅผ ๋•Œ๋งŒ ๊ณ ์œ  ์ด๋ฒคํŠธ count๋ฅผ ์ถ”๊ฐ€๋กœ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  • ์ธ์ž ์—†์ด main.py๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ์‹คํ–‰์ž…๋‹ˆ๋‹ค.

DB ์ดˆ๊ธฐํ™”

/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/init_db.py

๋กœ์ปฌ FTP ์„œ๋ฒ„

/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/local_ftp_server.py

๋ฐฐ์น˜ ์‹คํ–‰

RUBI

/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/test.py \
  --input-date 2026-04-11 \
  --parser RUBI

RUPI

/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/test.py \
  --input-date 2026-04-11 \
  --parser RUPI

COMBINED

/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/test.py \
  --input-date 2026-04-11 \
  --parser COMBINED

ER_DOSE_RAW

ER_DOSE_DB_DSN='postgresql://user:password@host:5432/dbname' \
/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/main.py \
  --date 2026-04-11 \
  --parser ER_DOSE_RAW

ER_DOSE_EUV

ER_DOSE_DB_DSN='postgresql://user:password@host:5432/dbname' \
/Users/parkjunho/PycharmProjects/PythonStudy/.venv/bin/python \
  /Users/parkjunho/PycharmProjects/PythonStudy/main.py \
  --date 2026-04-11 \
  --parser ER_DOSE_EUV

์ง์ ‘ ER Dose ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ER_DOSE_RAW๋ฅผ ๋‚ ์งœ ์—†์ด ์‹คํ–‰ํ•˜๋ฉด ์ตœ๊ทผ 2์ผ lookback ๋ชจ๋“œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

python3 -m er_dose.run_er_dose_batch \
  --parser ER_DOSE_RAW \
  --dsn 'postgresql://user:password@host:5432/dbname'
python3 -m er_dose.run_er_dose_batch \
  --date 2026-04-11 \
  --parser ER_DOSE_RAW \
  --dsn 'postgresql://user:password@host:5432/dbname'
python3 -m er_dose.run_er_dose_batch \
  --date 2026-04-11 \
  --parser ER_DOSE_EUV \
  --dsn 'postgresql://user:password@host:5432/dbname'

๊ธฐ์กด ์‹œ๊ฐ„ ๋ฒ”์œ„ ์ง์ ‘ ์ง€์ • ๋ฐฉ์‹๋„ ๊ณ„์† ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

python3 -m er_dose.run_er_dose_batch \
  --start-time 2026-04-11T00:00:00 \
  --end-time 2026-04-12T00:00:00 \
  --dsn 'postgresql://user:password@host:5432/dbname'

Airflow

์„ค์ •

์œ„์น˜: /Users/parkjunho/PycharmProjects/PythonStudy/ftp_batch/config/local_test_settings.py

์ฃผ์š” ๊ฐ’:

  • CLIENT_FTP_ROOT_PATH = "/RUIP"
  • TEXT_FTP_ROOT_PATH = "/RUBI"
  • SERVER_FTP_ROOT_PATH = "/rbi"
  • LOCAL_WORK_DIR
  • LOCAL_DB_PATH
  • RUPI_SCALE_PERCENT

๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ / ๋กœ์ปฌ ๋ณด๊ด€ ์ •์ฑ…

  • RUBI๋Š” DB commit ์„ฑ๊ณต ์ „์—๋Š” FTP ์›๋ณธ์„ ์‚ญ์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • COMBINED์—์„œ ๋งค์นญ๋œ ํ•ญ๋ชฉ์€ ์—…๋กœ๋“œ ์„ฑ๊ณต ํ›„ DB commit, ๊ทธ ๋‹ค์Œ FTP ์›๋ณธ ์‚ญ์ œ ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ raw txt/tif๋Š” scratch ํŒŒ์ผ์ด๋ผ ์ฒ˜๋ฆฌ ํ›„ ์ฆ‰์‹œ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ png๋Š” ์žฌ์—…๋กœ๋“œ ์บ์‹œ๋กœ 3์ผ ์œ ์ง€ํ•˜๊ณ , ๋ฐฐ์น˜ ์‹œ์ž‘ ์‹œ 3์ผ ์ง€๋‚œ ํŒŒ์ผ๋งŒ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ•œ๊ณ„

  • commit ์„ฑ๊ณต ํ›„ FTP delete ์‹คํŒจ ์žฌ์‹œ๋„ ํ๋Š” ์•„์ง ์—†์Šต๋‹ˆ๋‹ค.
  • DB๋Š” SQLite ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.
  • scan()์€ ๋‚ ์งœ ํด๋” ๋ฐ”๋กœ ์•„๋ž˜ ํŒŒ์ผ๋งŒ ์ฝ๊ณ  ์žฌ๊ท€ ์Šค์บ”์€ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๋ฒ”์œ„์— ๋„ฃ์ง€ ์•Š์€ ๊ฒƒ

  • .env ๊ธฐ๋ฐ˜ ์„ค์ • ๋กœ๋”ฉ
  • ON CONFLICT DO NOTHING ๊ธฐ๋ฐ˜ ์ค‘๋ณต ์ฒ˜๋ฆฌ ์ •์ฑ… ๋ณ€๊ฒฝ
  • FTP ์žฌ๊ท€ ๋””๋ ‰ํ† ๋ฆฌ ์‚ญ์ œ ์œ ํ‹ธ
  • 00:00 ~ 01:59 ์ „๋‚ ๋งŒ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹œ๊ฐ„ ๋ถ„๊ธฐ
  • PostgreSQL ์ „ํ™˜

์ž์„ธํ•œ ๋งค์นญ ๊ทœ์น™์€ /Users/parkjunho/PycharmProjects/PythonStudy/IMAGE_TEXT_MATCHING.md ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.