Parquet Page ๊ตฌ์กฐ
๋ฐ์ดํฐ ์์ง๋์ด๋ก์ ์ผ์ ํ์ง ๋ฒ์จ 3๋
์ด ๋์๋คโฆ! ๊ทธ๋ฐ๋ฐ ๊ทธ๋์ ๋งจ๋ ์จ์จ .parquet ํฌ๋งท์ ๋ด๊ฐ ์ ๋๋ก ์๊ณ ์๋๊ฒ ๋ง๋?๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. Parquet๋ ํฌ๋งท์ด v2๊น์ง ๋์จ ๊ฝค ์ค๋๋๊ณ ์ ์ ๊น์ ํฌ๋งท์ด๊ณ , ๋ ์ต๊ทผ์๋ Parquet Variant ํ์
๊ด๋ จํด์๋ ์์
์ ํ๊ณ ์๋๋ฐ, ๋ด๊ฐ ์ด ํฌ๋งท์ ๋ํด ์์ ์๊ฒ ์๊ธฐํ ์ ์๋์ง ์ค์ค๋ก ๋์๋ณด๊ฒ ๋์๋ค. ๊ทธ๋์ ์ด๋ฒ ๊ธฐํ์ Parquet๋ฅผ ๋ค์ ๋ณด๊ณ ๋ด๊ฐ ๋ถ์กฑํ๋ ๋ถ๋ถ๋ค์ ์ฑ์๋ฃ์ด๋ณด๋ ค๊ณ ํ๋ค.
์ง๋ ํฌ์คํธ์์ Parquet ํฌ๋งท์ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ณด์๋ค. ์ด๋ฒ ํฌ์คํธ๋ Parquet์์ ์ปฌ๋ผ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ ์ต์ ๋จ์์ธ Page ๊ตฌ์กฐ์ ๋ํด ์ดํด๋ณธ๋ค.

Dictionary Page
์ปฌ๋ผ ๋ฐ์ดํฐ๋ฅผ Parquet์ ์ ์ฅํ ๋, ๋ฐ์ดํฐ์ ์นด๋๋๋ฆฌํฐ์ ๋ฐ๋ผ์ Dictionary Encoding ํ๋ ๊ฒฝ์ฐ๋ ์๋ค. ์นด๋๋๋ฆฌํฐ๊ฐ ๋ฎ๋ค๋ฉด Dictionary Encoding ๋๋ค.
๋ชจ๋ primitive ํ์ ์ Dictionary Encoding์ด ๊ฐ๋ฅํ๋ค. Parquet write๋ ์ฒ์์๋ Dictionary Encoding์ผ๋ก ๋ฐ์ดํฐ ์ฐ๊ธฐ๋ฅผ ์๋ํ๋ค. ๊ทธ๋ฌ๋ค๊ฐ ๊ณ ์ ๊ฐ์ด ๋๋ฌด ๋ง์์ ธ์ Dictionary Page ํฌ๊ธฐ๊ฐ ์ผ์ ํฌ๊ธฐ ์ด์์ผ๋ก ์ปค์ง๋ฉด, ๊ทธ๋๋ Dictionary Encoding์ ํฌ๊ธฐํ๊ณ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ ํํ๋ค.
spark์์๋ parquet.dictionary.page.size = 1mb ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ธํ
๋์ด ์๊ณ , ์ config๋ก ์กฐ์ ํ ์ ์๋ค. ์ด ํฌ๊ธฐ๋ฅผ ๋์ผ๋ฉด, ํด๋น Column Chunk์ Dictionary Page ์์ด Data Page๋ง ์กด์ฌํ๋ค. ์๊ฐํด๋ณด๋ฉด, Column Chunk์ ์ฌ์ด์ฆ๋ 1mb๋ก ์ ํ๋๊ธฐ ๋๋ฌธ์, Dictionary Page์ ์ต๋ ํฌ๊ธฐ๋ 1mb๋ก ์ ํ๋๋๊ฒ์ด ์์ฐ์ค๋ฝ๊ธด ํ๋ค! ํ์ง๋ง, Data Page์ Dictionary Page๋ ์๋ก ๋
๋ฆฝ์ ์ธ ์ค์ ์ด๋ค. ๋ Page์ ์ฌ์ด์ฆ limit์ด ๊ฐ์๊ฒ ์๋๋ ์ธํ
์ด๊ฒ ์ง๋ง, ์ค์ ๋์ํ ๋๋ ์๋ก ๋ค๋ฅด๊ฒ ๋์ํ๋ค๋ ๊ฒ! (์ ๋๋ก ์ ์๊ฑด๊ฐ..!?)
parquet.block.size-> Row Group์ ํฌ๊ธฐ (default: 128mb)parquet.page.size-> Data Page์ ํฌ๊ธฐ ์ ํ (default: 1mb)parquet.dictionary.page.size-> Dictionary Page์ ํฌ๊ธฐ ์ ํ (default: 1mb)
์ปฌ๋ผ ๋ฐ์ดํฐ์ ๊ฐ์ Row Group์ผ๋ก ๋๋ ์ ์ ์ฅ๋๋ค. ๊ทธ๋ฐ๋ฐ Row Group์ผ๋ก ๋ถํ ๋ ์ปฌ๋ผ ๋ฐ์ดํฐ๋ง๋ค ์นด๋๋๋ฆฌํฐ๊ฐ ๋ค๋ฅผ ์ ์๋ค. ๊ทธ๋์, Row Group 0์์๋ Column Chunk์ Diciontary Encoding์ด ์ ์ฉ๋์ง๋ง, Row Group 1์์ fallback -> plain encoding์ผ๋ก ์ ์ฅ๋๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
Row Group(์ค์ง์ ์ผ๋ก Chunk Column) ๋ด์์ ํด๋น ์ปฌ๋ผ์ด Dictionary Encoding์ด ๊ฐ๋ฅํ๋ค๋ฉด, Chunk Column์ ์ด๋ ๊ฒ ๊ตฌ์ฑ๋๋ค.
Dictionary Page -> Data Page 0 -> Data Page 1 -> โฆ -> Data Page N
Definition Level
์๊ฑด Page์ ์ ์ฅํ ๋ฐ์ดํฐ์ null ๊ฐ์ด ์ด๋์ด๋์ ์๋์ง ํ์ํ๋ bit array๋ค. Parquet Page ๊ตฌ์กฐ์์ ์ ์ผ ์ฌ์ด ๊ฐ๋ ์ด๋ค. ใ ใ
N๋ฒ์งธ ์์น์ ๋ฐ์ดํฐ๊ฐ null์ด๋ ์๋๋๋ฅผ ๋ณธ๋ค. ๊ทธ๋์ null ๊ธฐ๋ฐ ํํฐ๋ฅผ ํ ๋, null count๋ฅผ ํ ๋๋ ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฝ๊ณ Definition Level์ ๋ณด๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ๊ทผํ๊ณ null count๋ฅผ ์ธ๋ฉด ๋๋ค.
Repetition Level
๋ชจ๋ ๊ฐ์ด flatํ primitive ํ์
์์๋ repetition level์ด ์ ๋ถ zero bit์ด ๋๊ธฐ ๋๋ฌธ์ ์๋ฏธ๊ฐ ์๋ค. rep level์ด ์๋ฏธ๊ฐ ์์ผ๋ ค๋ฉด, ARRAY, STRUCT, VARIANT ํ์
์ผ ๋๋ค.
ARRAY
์๋ฅผ ๋ค์ด, tags ARRAY<STRING> ์ปฌ๋ผ์ด ์๊ณ , ๊ทธ ๊ฐ์ด ์๋์ ๊ฐ๋ค๊ณ ํ์.
row 0: tags = ["a", "b", "c"]
row 1: tags = ["d"]
์ด๊ฑธ flatํ๊ฒ ํผ์น๋ฉด,
values: a b c d
rep: 0 1 1 0
def: 1 1 1 1
์ด์ ๋ฌด์จ ์๋ฏธ์ผ๊น? ์ถ๊ฒ ์ง๋ง, ์ผ๋จ rep level์ ํจํด์ ์ง์คํ๋ผ. rep bit = 0์ด๋ฉด, ์๋ก์ด ๋ฐฐ์ด์ ์์ ๊ฐ์ด๋ผ๋ ๊ฑฐ๋ค. ์ฆ, ๋ฐฐ์ด์ ์์ํ๋ ๊ดํธ ( ๋๋ [๋ผ๋ ๊ฒ์ด๋ค. ๋ฐ๋๋ก rep bit = 1์ด๋ฉด, ์ด์ ์ ์ด์๋ค ๋ฐฐ์ด์ด ๊ณ์๋๋ค๋ ๊ฒ์ด๋ค. ์ฆ, ์ฝค๋ง ,๋ผ๋ ๊ฒ์ด๋ค.
์ด์ ์ด ๋ด์ฉ์ ๊ฐ์ง๊ณ ์์ ํํ์ ๋ค์ ์ ์ด๋ณด์.
values: a b c d
rep: 0 1 1 0
rep*: [ , , ][...
empty array, null array
row 0: tags = ["a", "b", "c"]
row 1: tags = []
row 2: tags = ["d"]
๋ฐ์ดํฐ ์ฌ์ด์ empty array []๊ฐ ๋ผ์ด๋ ์ผ์ด์ค๋ฅผ ๋ณด์. ์ด๋, def level์ด ๋น๋ฐฐ์ด๊ณผ null ๋ฐฐ์ด์ ๊ตฌ๋ถํ๊ธฐ ์ํด ์ด๋ ๊ฒ ์ ์๋๋ค.
def=0: tags ์์ฒด๊ฐ nullldef=1: tags๋ ์กด์ฌํ์ง๋ง ๋น์ด์์. empty arraydef=2: tags์ ๊ฐ์ด ์์.
๊ทธ๋์ ํํ์์ด ์ด๋ ๊ฒ ๋๋ค.
values: a b c (empty) d
rep: 0 1 1 0 0
def: 2 2 2 1 2
Nested Array
์ด๋ฒ์๋ ๋ฐฐ์ด์ธ๋ฐ, ์ค์ฒฉ ๋ฐฐ์ด์ด๋ค. items ARRAY<ARRAY<STRING>> ์ปฌ๋ผ์ด ์๋ค๊ณ ํ์. ์ด ์ปฌ๋ผ์ ์์ดํ
๋ชฉ๋ก์ ๋ด๋๋ฐ, ๊ทธ ์์๋ ๊ทธ ์์ดํ
์ด ๊ฐ์ง tag ์ ๋ณด๋ฅผ ๊ฐ๋๋ค.
row 0: items = [ {tags: ["a", "b"]}, {tags: ["c"]}]
row 1: items = [ {tags: []} ]
row 2: items = [ {tags: ["d"]} ]
row 3: items = []
row 4: items = null
def level์ ์ด๋ ๊ฒ ์ ์๋๋ค.
- def=0 -> ์์ดํ
์์ฒด๊ฐ null ->
null - def=1 -> items๋ ์์ง๋ง, ๋น์ด์์. ->
[] - def=2 -> items๋ ์์ง๋ง, tags๊ฐ ๋น์ด์์. ->
[[]] - def=3 -> items๋ ์๊ณ , tag์๋ ๊ฐ์ด ์์. ->
[["a"]]
rep level์ ์ด๋ ๊ฒ ์ ์๋๋ค.
- rep=0 -> ์ row์ ์์ -> item์ ์ฌ๋ ๊ดํธ
[ - rep=1 -> ๊ฐ์ row ์์์ ์ item์ด ์์๋๋ค. -> tags๋ฅผ ์ฌ๋ ๊ดํธ
[ {tags: - rep=2 -> ๊ฐ์ item ์์์ tags ๊ฐ์ด ๊ณ์ ์ด์ด์ง.
์ด์ ์ ์๋๋ก rep/dev level๋ก ํํํ๋ฉด,
value: a b c [[]] d [] null
rep: 0 2 1 0 0 0 0
def: 3 3 3 2 3 1 0
STRUCT
์ด๋ฐ ์คํค๋ง๊ฐ ์๋ค๊ณ ํ์.
message Order {
optitional group address {
required string city;
optional string zipcode;
}
}
๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋
row 0: address = {city: "Seoul", zipcode: "04524"}
row 0: address = {city: "Pohang", zipcode: null}
row 0: address = null
STRUCT ํ์
์ leaf ์ปฌ๋ผ์ผ๋ก ๋ถํดํด์ ์ ์ฅํ๋ค. ์ฆ, address.city, address.zipcode๊ฐ ๋ณ๋์ Column Chunk๋ก ์ ์ฅ๋๋ค. ๊ทธ๋์ STRUCT ํ์
์ ๊ตฌ์กฐ์ฒด ์ปฌ๋ผ์์๋ ๋น ๋ฅธ ์ฟผ๋ฆฌ๊ฐ ๊ฐ๋ฅํ ๊ฒ์ด๋ค.
def/rep level๋ ๊ฐ leaf ์ปฌ๋ผ ๊ธฐ์ค์ผ๋ก ์ ํด์ง๋ค. ์๊ฑด primitive ํ์ ๊ณผ ๋น์ทํ๊ฒ ์ด๋ค์ง๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์์๋ ์๋ต ํ๊ฒ ๋ค.
์ด๋ ๊ฒ STRUCT ํ์
์ leaf ์ปฌ๋ผ์ผ๋ก ๋ถํดํด์ ๊ฐ๊ฐ ์ ์ฅํ๋ ๊ฑธ โShreddingโ์ด๋ผ๊ณ ํ๋ค. address ์ปฌ๋ผ ์์ฒด๋ Column Chunk๊ฐ ์์ผ๋ฉฐ, STRUCT ๊ตฌ์กฐ ์ ๋ณด๋ Parquet ์คํค๋ง์๋ง ์กด์ฌํ๋ค.
๋ฐ๋๋ก STRUCT ํ์
์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๊ณผ์ ์ Assembly๋ผ๊ณ ํ๋ค. ๋ถํด๋ leaf ์ปฌ๋ผ์ ์๋์ STRUCT ๊ตฌ์กฐ๋ก ๋ณต์ํ๋ ๊ฒ!
DATA_PAGE_V2
Parquet 1.x ํ๋ฐ์ ์ถ๊ฐ๋ ์ด ํฌ๋งท์ Data Page๋ฅผ ์ ์ฅํ๊ณ ์์ถํ ๋, rep/def level์ ์์ถํ์ง ์๋๋ค.
๋ณธ๋ DATA_PAGE์์ rep+def+values ์ ์ฒด๋ฅผ ์์ถํด์ ์ ์ฅํ๋ค. ๊ทธ๋ฐ๋ฐ, ์ด๋ ๊ฒ ํ๋ null ๊ฐ์ ์ฐพ์ ๋, Page ์ ์ฒด๋ฅผ ์์ถ ํด์ ํด์ผ ๊ทธ ์์ def level์ ๋ณด๊ณ null ๊ฐ ํํฐ๋ง์ด ๊ฐ๋ฅํ๋ค.
DATA_PAGE_V2๋ ์ค์ง values ๊ฐ๋ง ์์ถํด์ ์ ์ฅํ๋ค. rep/def level์ ์์ถํ์ง ์๊ณ ๊ทธ๋๋ก ์ ์ฅํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด, null ํํฐ๋ง์ ์์ถํด์ ์์ด ๋น ๋ฅด๊ฒ ํ ์ ์๋ค.
Spark์์๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก DATA_PAGE(v1)์ ์ฌ์ฉํ๋ค. v2๋ฅผ ์ฐ๋ ค๋ฉด, spark.sql.parquet.dataPageVersion=v2๋ก ๋ช
์ํด์ค์ผ ํ๋ค.