ค้นหา CSV โดยตรงกับ DuckDB

Dec 29 2022
คุณได้รับมอบหมายให้ทำสิ่งใดสิ่งหนึ่งต่อไปนี้: — โหลดไฟล์ csv ใหม่ลงใน BigQuery เพื่อการวิเคราะห์ — เพิ่มไฟล์ใหม่ไปยังไปป์ไลน์ข้อมูลของคุณ — ทำการตรวจสอบคุณภาพข้อมูลแบบ light-touch ในไฟล์ของผู้ขาย - คุณเข้าถึงสิ่งที่ใกล้เคียงที่สุด และเครื่องมือที่คุณคุ้นเคยมากที่สุด ปกติมันต้องโหลดมาไว้ใน Excel ใช่ไหมครับ? ซึ่งทำให้คุณไป
Duckdb และ csv

คุณได้รับมอบหมายให้ทำสิ่งใดสิ่งหนึ่งต่อไปนี้:
— โหลดไฟล์ csv ใหม่ลงใน BigQuery เพื่อการวิเคราะห์
— เพิ่มไฟล์ใหม่ลงในไปป์ไลน์ข้อมูลของคุณ
— ทำการตรวจสอบคุณภาพข้อมูลแบบ light-touch ในไฟล์ของผู้ขาย

คุณเข้าถึงเครื่องมือที่ใกล้เคียงและคุ้นเคยที่สุดที่คุณรู้จัก ปกติมันต้องโหลดมาไว้ใน Excel ใช่ไหมครับ? ซึ่งทำให้คุณไป แต่ไฟล์มีขนาด 600MB และยาวกว่า 1.2M บรรทัด Excel บอกคุณว่าสามารถโหลดไฟล์ได้เพียงบางส่วนเท่านั้น

ตกลงแล้วจะทำอย่างไรต่อไป

คุณอาจใช้ GCP/BigQuery ดังนั้นคุณจึงคลิกและปล่อยทิ้ง แต่ BQ บอกคุณว่าตำแหน่ง 1023845 นั้นไม่ดี คุณจะหาตำแหน่งไบต์นั้นในไฟล์ได้อย่างไร <ถอนหายใจ>

คุณค้นหา Stackoverflow และพวกเขาบอกให้คุณใช้แพนด้า มันพาคุณไปถึงที่นั่น แต่ความเร็วของคุณถูกขัดขวางเพราะคุณลืมทุกคำสั่ง บางทีคุณอาจใช้ ChatGPT แต่ต้องการคำตอบทันทีและต้องการคำตอบอย่างรวดเร็ว

จะดีกว่ามั้ยถ้าแค่ `เลือก * จาก output.csv`

คุณทำได้ทั้งหมด

ขั้นตอนที่ 1

brew install duckdb

> duckdb
D> select * from ‘output.csv*’

คุณยังสามารถใช้ `data/*.csv` หรือแม้แต่ส่วนขยายอื่นๆ เช่น `data/*.parquet`

การแก้ไขปัญหา

ดังนั้นการโหลด csv จึงทำได้ไม่ดีนัก คุณเริ่มด้วย Duckdb แล้ว มันพูด


Error: Invalid Input Error: Could not convert string ‘Column_1’ to INT32 
in column “Column_1”, at line 100002.

สิ่งแรกที่เราควรทำคือสร้างมุมมองบน csv ของคุณด้วยหมายเลขบรรทัดบางบรรทัด เพื่อให้คุณสามารถเริ่มตรวจสอบไฟล์และทำการตรวจสอบคุณภาพแบบ light-touch


create sequence seq_id start 1;

D> create or replace view test_1 as SELECT nextval(‘seq_id’) as seq_id, * 
from read_csv(‘output.csv’, ALL_VARCHAR=1, AUTO_DETECT=TRUE);

couple of things here, of reference is https://duckdb.org/docs/data/csv

  • คุณมีข้อมูลที่ไม่ดี Duckdb สุ่มตัวอย่างทุกๆ 100 บรรทัดและคาดเดาประเภทคอลัมน์ ข้อมูลบางอย่างในคอลัมน์ของคุณไม่ใช่ข้อมูลที่ควรจะเป็น `ALL_VARCHAR` ให้คุณโหลดได้ทั้งหมด โดยไม่คำนึงถึงประเภทสำหรับการวิเคราะห์
    — `AUTO_DETECT` หมายถึงการใช้แถวแรก เดาว่าควรมีคอลัมน์กี่คอลัมน์ มิฉะนั้นเราจะต้องพิมพ์ด้วยตนเอง `columns={'Column_1,', 'Column_2…}'`

ณ จุดนี้ เนื่องจากลำดับของเราถูกนับอยู่เสมอ จึงเป็นเวลาที่ดีที่จะล็อคลำดับและทำให้มุมมองเป็นจริงด้วยหมายเลขบรรทัดของเรา


create table test_1_mv as (select * from test_1);


 — it seems that line numbers in errors are zero-indexed
 — however you cannot start a sequence from 0
 — so we need to subtract `1` from the id
select * from test_1 where seq_id = 100001
┌────────┬───────────────┬──────────────┬──┐
│ seq_id │ Column_1      │ Column_2     │  │
│ int64  │ varchar       │ varchar      │  │
├────────┼───────────────┼──────────────┼──┤
│ 100001 │ Column_1_text │ Column_2_text│  │
├────────┴───────────────┴──────────────┴──┤
│ 1 rows                                   │
└──────────────────────────────────────────┘

ให้ค้นหาแถวที่ละเมิดทั้งหมด ความคิดแรกของฉันคือมองหาแถวทั้งหมดที่มี `Column_1_text` อยู่ในนั้น


select * from test_1 where column_1 = ‘Column_1_text’;


select * from test_1
where regexp_matches(Column_1, ‘[a-zA-Z]’)


delete from test_1_mv where seq_id in (select seq_id from test_1_mv 
where regexp_matches(Column_1, ‘[a-zA-Z]’));

เขียนไฟล์ใหม่ — ส่งออก

หากต้องการส่งออกข้อมูลจากตารางเป็นไฟล์ CSV ให้ใช้คำสั่ง 'COPY'


COPY test_1_mv TO ‘output_cleaned.csv’ (HEADER, DELIMITER ‘,’);