TL;DR

  • source : https://github.com/pgvector/pgvector
  • ์ „๋ฌธ์ ์ธ vector DB๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์ง€๋งŒ postgreSQL์—์„œ ์‰ฝ๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ํฐ ๋ฉ”๋ฆฌํŠธ

1. PGVector๋ž€

PostgreSQL์— ๋ฒกํ„ฐ๋ฅผ ์ง์ ‘ ์ €์žฅํ•ด similarity search ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜คํ”ˆ ์†Œ์Šค ํ™•์žฅ ๋ชจ๋“ˆ๋กœ ๋ฌธ์„œ์˜ ์˜๋ฏธ์  ์œ ์‚ฌ๋„ ๊ฒ€์ƒ‰, ์ถ”์ฒœ ์‹œ์Šคํ…œ ๋“ฑ ๋ฒกํ„ฐ ๊ธฐ๋ฐ˜ AI ์‘์šฉ์„ ์ „๋ฌธ ๋ฒกํ„ฐ DB ์—†์ด๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋˜ํ•œ PostgreSQL์˜ ACID ํŠธ๋žœ์žญ์…˜, ๋ณต์ œ, ๋ฐฑ์—…, JOIN ๋“ฑ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ๊ณผ ํ†ตํ•ฉ๋˜๋ฏ€๋กœ ์ผ๊ด€์„ฑ๊ณผ ๊ด€๋ฆฌ ์ธก๋ฉด์—์„œ ์žฅ์ ์ด ์žˆ๋‹ค.


2. ํŠน์ง•

  1. ๋‹ค์–‘ํ•œ ๊ฑฐ๋ฆฌ ํ•จ์ˆ˜ ์ง€์› : ๋ฒกํ„ฐ ๊ฐ„ ์œ ์‚ฌ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ๊ฑฐ๋ฆฌ/์œ ์‚ฌ๋„ ์ง€ํ‘œ๋ฅผ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋ฉฐ, ์—ฐ์‚ฐ์ž๋กœ ๊ฐ„ํŽธํžˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

    • ์œ ์‚ฌ๋„ ์ข…๋ฅ˜ : ๊ฐ’์ด ์ž‘์„์ˆ˜๋ก ๋” ๊ฐ€๊น๋‹ค๊ณ  ํŒ๋‹จ
      • L2 distance <->
      • Inner product <#> : ๊ฐ’์ด ์ž‘์„์ˆ˜๋ก ๋” ๊ฐ€๊น๊ฒŒ ํ•ด์„ํ•˜๊ธฐ ์œ„ํ•ด ์Œ์ˆ˜๋ฅผ ๋ถ™์—ฌ์„œ ๋ฐ˜ํ™˜
      • Cosine distance <=> : 1-cosine similarity ๋ฅผ ๋ฐ˜ํ™˜
      • L1 distance <+>
      • Hamming <~>
      • Jaccard <\%>
  2. ๋ฒกํ„ฐ ์ „์šฉ ๋ฐ์ดํ„ฐ ํƒ€์ž…: vector(n) ํ˜•ํƒœ๋กœ n์ฐจ์› ๋ฒกํ„ฐ ํƒ€์ž…์„ ์ •์˜ํ•˜์—ฌ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

    • ๋‹จ์ผ ์ •๋ฐ€๋„(float4) ๋ฒกํ„ฐ ์™ธ์—๋„ ์ ˆ๋ฐ˜ ์ •๋ฐ€๋„(float2)์ธ halfvec, ํฌ์†Œ๋ฒกํ„ฐ sparsevec, ์ด์ง„๋ฒกํ„ฐ bit ๋“ฑ์˜ ํƒ€์ž…์„ ์ œ๊ณต
    • vector ํƒ€์ž…์€ ์ตœ๋Œ€ 2,000์ฐจ์›๊นŒ์ง€ ์ง€์›(halfvec์€ 4,000์ฐจ์›)
    • 2,000์ฐจ์›์„ ์ดˆ๊ณผํ•˜๋Š” ์ž„๋ฒ ๋”ฉ์€ PCA ๋“ฑ ์ฐจ์› ์ถ•์†Œ๋ฅผ ํ†ตํ•ด ์ค„์ด๊ฑฐ๋‚˜, ๋ถ€๋“์ดํ•œ ๊ฒฝ์šฐ PGVector ๋Œ€์‹  ๋ฐฐ์—ด ์ปฌ๋Ÿผ(double precision[] ๋“ฑ)์— ์ €์žฅํ•  ์ˆ˜๋„ ์žˆ์œผ๋‚˜ ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•œ ๋น ๋ฅธ ๊ฒ€์ƒ‰์€ ์ œํ•œ
  3. ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰๊ณผ ๊ทผ์‚ฌ ์ตœ๊ทผ์ ‘ ์ด์›ƒ(ANN) ๊ฒ€์ƒ‰ : ๊ธฐ๋ณธ์ ์œผ๋กœ ์™„์ „ ํƒ์ƒ‰(์ •ํ™•ํ•œ ์ตœ๊ทผ์ ‘ ์ด์›ƒ ๊ฒ€์ƒ‰)

    • ๋ฐ˜๋ฉด ๋Œ€๋Ÿ‰์˜ ๋ฒกํ„ฐ์— ๋Œ€ํ•ด ๋” ๋น ๋ฅธ ๊ฒ€์ƒ‰์ด ํ•„์š”ํ•˜๋ฉด ๊ทผ์‚ฌ ์ตœ๊ทผ์ ‘ ํƒ์ƒ‰(ANN) ์„ ์ง€์›ํ•˜๋Š” ํŠน์ˆ˜ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Œ
    • HNSW(Hierarchical Navigable Small World)์™€ IVFFlat(Inverted File Index) ๋‘ ๊ฐ€์ง€ ANN ์ธ๋ฑ์Šค๋ฅผ ์ œ๊ณต
    • ์ผ๋ถ€ ์ •ํ™•๋„๋ฅผ ํฌ์ƒํ•˜๊ณ ๋„ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ๋Œ€ํญ ํ–ฅ์ƒ
  4. SQL๊ณผ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ†ตํ•ฉ: PGVector๋กœ ์ €์žฅํ•œ ๋ฒกํ„ฐ๋Š” ์ผ๋ฐ˜ SQL ์ฟผ๋ฆฌ์—์„œ ๋‹ค๋ฅธ ์ปฌ๋Ÿผ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

    • ๋ฒกํ„ฐ ์œ ์‚ฌ๋„ ์กฐ๊ฑด๊ณผ ๋‹ค๋ฅธ ์†์„ฑ์˜ ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๊ฒฐํ•ฉํ•˜๊ฑฐ๋‚˜, JOIN์„ ํ†ตํ•ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์™€ ์ž„๋ฒ ๋”ฉ์„ ํ•จ๊ป˜ ํ™œ์šฉํ•˜๋Š” ๋ณต์žกํ•œ ์งˆ์˜๋ฅผ ์ˆ˜ํ–‰
    • ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ์ „์šฉ DB๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋ณด๋‹ค ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์ด ๋†’๊ณ , ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ์œ ์ง€๊ฐ€ ์šฉ์ด
    • PostgreSQL ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ๋ชจ๋“  ์–ธ์–ด์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด(C, Python, Java, Go ๋“ฑ) ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋‹ค์–‘ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—ฐ๊ณ„ํ•˜๊ธฐ ์‰ฌ์›€
  5. ํ™•์žฅ์„ฑ๊ณผ ๋Œ€์šฉ๋Ÿ‰ ์ฒ˜๋ฆฌ : PGVector๋Š” ์‹ค์„ธ๊ณ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์— ๋งž๊ฒŒ ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ ์ด์ƒ์˜ ๋ฒกํ„ฐ๋„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„

    • PostgreSQL ์ž์ฒด์˜ ํŠผํŠผํ•œ ์Šค์ผ€์ผ ์—…/์•„์›ƒ ๊ธฐ๋Šฅ(ํŒŒํ‹ฐ์…”๋‹, ๋ณ‘๋ ฌ ์ฟผ๋ฆฌ, ๋ณต์ œ ๋“ฑ)์„ ํ•จ๊ป˜ ํ™œ์šฉํ•˜๋ฉด ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•ด๋„ ์•ˆ์ •์ ์œผ๋กœ ์„ฑ๋Šฅ์„ ์œ ์ง€
      • ์˜ˆ๋ฅผ ๋“ค์–ด, ์ƒ‰์ธ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ PostgreSQL์˜ parallel sequential scan1์„ ํ†ตํ•ด ๋‹ค์ˆ˜ ์ฝ”์–ด๋กœ ์œ ์‚ฌ๋„ ์—ฐ์‚ฐ์„ ๋ณ‘๋ ฌํ™”
      • ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ํ›„ ์ธ๋ฑ์‹ฑ์ด๋‚˜ ํŒŒํ‹ฐ์…˜ ๋‚˜๋ˆ„๊ธฐ๋ฅผ ํ†ตํ•ด ๋Œ€๊ทœ๋ชจ ๋ฒกํ„ฐ์…‹์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์Œ
    • PostgreSQL์˜ WAL ๋กœ๊ทธ2๋ฅผ ํ†ตํ•œ PITR3, ์ŠคํŠธ๋ฆฌ๋ฐ ๋ณต์ œ4๋„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ ๋˜ํ•œ ๊ณ ๊ฐ€์šฉ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Œ

3. ์žฅ๋‹จ์ 

์žฅ์ 
  1. ๊ธฐ์กด DB์™€์˜ ํ†ตํ•ฉ

    • ๋ณ„๋„์˜ ๋ฒกํ„ฐ ์ „์šฉ DB๋ฅผ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด PostgreSQL ํ™˜๊ฒฝ์— ํ†ตํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์šด์˜ ๋ณต์žก๋„๊ฐ€ ๋‚ฎ์Œ
    • ํŠธ๋žœ์žญ์…˜, ๋ณด์•ˆ, ๋ฐฑ์—… ๋“ฑ Postgres์˜ ์„ฑ์ˆ™ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
    • ํ•˜๋‚˜์˜ DB์—์„œ ์—…๋ฌด ๋ฐ์ดํ„ฐ์™€ ์ž„๋ฒ ๋”ฉ์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์ด ๋†’๊ณ , ํ‘œ์ค€ SQL๋กœ ์งˆ์˜ ๊ฐ€๋Šฅ
    • ํŒ€์›๋“ค์ด ํ•™์Šต ์ปค๋ธŒ ์—†์ด ํ™œ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์ด ๋†’์Œ
  2. ๋‹ค์–‘ํ•œ ํ™œ์šฉ๊ณผ ์ •ํ™•์„ฑ

    • ๊ธฐ๋ณธ ์„ค์ •์—์„œ ์ •ํ™•ํ•œ ์ตœ๊ทผ์ ‘ ์ด์›ƒ ๊ฒ€์ƒ‰(์™„์ „ ํƒ์ƒ‰)์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ๊ฒฐ๊ณผ์˜ ์ •ํ™•๋„(์žฌํ˜„์œจ) ๋ฉด์—์„œ ์šฐ์ˆ˜
    • ํ•„์š”ํ•  ๊ฒฝ์šฐ ๋ฒกํ„ฐ ์œ ์‚ฌ๋„ ์ž„๊ณ„๊ฐ’์„ ์ง€์ •ํ•œ ๋ฒ”์œ„ ๊ฒ€์ƒ‰๋„ ๊ฐ€๋Šฅํ•˜๋ฉฐ (WHERE embedding โ†> โ€˜๋ฒกํ„ฐโ€™ < ์ž„๊ณ„๊ฐ’ ํ˜•ํƒœ ), SUM/AVG ๊ฐ™์€ ์ง‘๊ณ„ํ•จ์ˆ˜๋„ ๋ฒกํ„ฐ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด ํ†ต๊ณ„ ๋ฒกํ„ฐ ์‚ฐ์ถœ์—๋„ ํ™œ์šฉ ๊ฐ€๋Šฅ
    • ์‘์šฉ ๋ถ„์•ผ๋„ ๊ฒ€์ƒ‰, ์ถ”์ฒœ, ์ด์ƒํƒ์ง€ ๋“ฑ ๋ฒ”์šฉ์ ์ด๋ฉฐ, ํ…์ŠคํŠธ ์ž„๋ฒ ๋”ฉ๋ถ€ํ„ฐ ์ด๋ฏธ์ง€ ์ž„๋ฒ ๋”ฉ๊นŒ์ง€ ํญ๋„“๊ฒŒ ์ง€์›
  3. ํ™•์žฅ์„ฑ & ์„ฑ๋Šฅ ์„ ํƒ์ง€

    • ๋ฐ์ดํ„ฐ ๊ทœ๋ชจ๋‚˜ ์š”๊ตฌ ์„ฑ๋Šฅ์— ๋งž์ถฐ ์œ ์—ฐํ•˜๊ฒŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Œ
    • ์ธ๋ฑ์Šค ์—†์ด๋„ ์ˆ˜๋งŒ~์ˆ˜์‹ญ๋งŒ ๊ฑด ๊ทœ๋ชจ์—์„œ๋Š” ์ถฉ๋ถ„ํžˆ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ , ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด ๊ทผ์‚ฌ ์ตœ๊ทผ์ ‘(ANN) ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Œ
    • HNSW ๊ทธ๋ž˜ํ”„ ์ธ๋ฑ์Šค์™€ IVFFlat ์ธ๋ฑ์Šค๋ฅผ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ํ•ฉํ•œ ๋ฐฉ์‹์„ ๊ณจ๋ผ ์†๋„์™€ ์ •ํ™•๋„์˜ ๊ท ํ˜•์„ ๋งž์ถœ ์ˆ˜ ์žˆ์Œ
      • HNSW๋Š” ๋†’์€ ์ •ํ™•๋„์™€ ๋น ๋ฅธ ์งˆ์˜๊ฐ€ ์žฅ์ ์ด๊ณ  IVFFlat์€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ์ ๊ณ  ์ธ๋ฑ์Šค ์ƒ์„ฑ์ด ๋น ๋ฅธ ์ ์ด ์žฅ์ 
    • ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ, ํŒŒํ‹ฐ์…”๋‹ ๋“ฑ PostgreSQL์˜ ์„ฑ๋Šฅ ๊ธฐ๋ฒ•์„ ํ•จ๊ป˜ ํ™œ์šฉํ•˜๋ฉด ๋Œ€๋Ÿ‰์˜ ๋ฒกํ„ฐ๋„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
  4. ์˜คํ”ˆ ์†Œ์Šค ๋ฐ ์ƒํƒœ๊ณ„

    • PGVector๋Š” ํ™œ๋ฐœํžˆ ๋ฐœ์ „ ์ค‘์ธ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋กœ์„œ PostgreSQL ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ๋‹ค์–‘ํ•œ ๊ธฐ์—…๋“ค์— ์˜ํ•ด ๊ฐœ์„ ๋˜๊ณ  ์žˆ์Œ
    • ๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฒ„์ „ ์—…์— ๋”ฐ๋ผ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋‚˜ ๊ธฐ๋Šฅ ์ถ”๊ฐ€(HNSW ์ง€์›, ์ธ๋ฑ์Šค ๋ณ‘๋ ฌ ๊ตฌ์ถ• ๋“ฑ)๋„ ๋น ๋ฅด๊ฒŒ ์ด๋ค„์ง€๊ณ  ์žˆ์Œ
    • LangChain ๊ฐ™์€ ์˜คํ”ˆ์†Œ์Šค ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์‰ฝ๊ฒŒ ์—ฐ๋™๋˜์–ด ๋ฐฑ์—”๋“œ ๋ฒกํ„ฐ์Šคํ† ์–ด๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  , Supabase ๋“ฑ์˜ ์„œ๋น„์Šค์—์„œ ๊ธฐ๋ณธ ์ง€์›ํ•˜๋Š” ๋“ฑ ์ƒํƒœ๊ณ„๊ฐ€ ํ˜•์„ฑ๋˜์–ด ์žˆ์Œ
๋‹จ์ 
  1. ์ „๋ฌธ ๋ฒกํ„ฐ DB ๋Œ€๋น„ ์„ฑ๋Šฅ ํ•œ๊ณ„

    • PGVector๋Š” ๋ฒ”์šฉ DB ์œ„์˜ ํ™•์žฅ์ธ ๋งŒํผ, ๋™์ผ ํ•˜๋“œ์›จ์–ด์—์„œ specialized ๋ฒกํ„ฐ ์ „์šฉ DB (Faiss, Milvus ๋“ฑ) ๋Œ€๋น„ ์ ˆ๋Œ€ ์„ฑ๋Šฅ์€ ๋‹ค์†Œ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ
    • ๋ชจ๋“  ์—ฐ์‚ฐ์ด CPU ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ค„์ง€๋ฉฐ, ๋Œ€์šฉ๋Ÿ‰ ๋ฒกํ„ฐ์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”๋‚˜ GPU ๊ฐ€์† ๋“ฑ์ด ์—†์œผ๋ฏ€๋กœ, ์ˆ˜์ฒœ๋งŒ ๋‹จ์œ„ ์ด์ƒ์˜ ๋ฒกํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•˜๋Š” ์ดˆ๋Œ€ํ˜• ์Šค์ผ€์ผ์—์„œ๋Š” ์„ฑ๋Šฅ ๋ณ‘๋ชฉ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ
    • ์ธ๋ฑ์Šค๋ฅผ ์“ฐ์ง€ ์•Š๋Š” ์ •ํ™• ๊ฒ€์ƒ‰์˜ ๊ฒฝ์šฐ ์„ ํ˜• ์‹œ๊ฐ„์ด ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์œผ๋ฉด ์†๋„๊ฐ€ ๋А๋ ค์ง€๊ณ , ๊ทผ์‚ฌ ๊ฒ€์ƒ‰๋„ ๋งค๊ฐœ๋ณ€์ˆ˜ ํŠœ๋‹์— ๋”ฐ๋ผ ์†๋„๊ฐ€ ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง
    • ๋Œ€๊ทœ๋ชจ ์„œ๋น„์Šค์—์„œ๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋ณ„๋„์˜ ๋ฒกํ„ฐDB๋ฅผ ๊ณ ๋ คํ•˜๊ฑฐ๋‚˜, PGVector ์‚ฌ์šฉ ์‹œ์—๋„ ์ถฉ๋ถ„ํ•œ ์ธ๋ฑ์Šค ํŠœ๋‹๊ณผ ์Šค์ผ€์ผ ์•„์›ƒ(์ƒค๋”ฉ/ํŒŒํ‹ฐ์…”๋‹) ์ „๋žต์ด ํ•„์š”
  2. ์ธ๋ฑ์‹ฑ ๊ด€๋ จ ์ œ์•ฝ

    • ANN ์ธ๋ฑ์Šค๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋ฉฐ, ์ž˜๋ชป ์„ค์ •ํ•  ๊ฒฝ์šฐ ๊ฒ€์ƒ‰ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์•„์งˆ ์ˆ˜ ์žˆ์Œ
      • IVFFlat ์ธ๋ฑ์Šค๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๊ฐœ์ˆ˜(lists) ๋ฅผ ์ ์ ˆํžˆ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฆฌ์ฝœ ์ €ํ•˜๋‚˜ ์กฐํšŒ ๋ถ€์ •ํ™•์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ณ  , ๋„ˆ๋ฌด ์ดˆ๊ธฐ ๋‹จ๊ณ„์— ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ๋ฐ์ดํ„ฐ ๋ถ„ํฌ๊ฐ€ ์น˜์šฐ์ณ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Œ
      • IVFFlat์€ ์ฟผ๋ฆฌ ์‹œ ๊ฒ€์ƒ‰ํ•  ๋ฆฌ์ŠคํŠธ ์ˆ˜(probes) ๋ฅผ ๋†’์—ฌ์•ผ ์ •ํ™•๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€๋Š”๋ฐ, ๋„ˆ๋ฌด ๋‚ฎ๊ฒŒ ์žก์œผ๋ฉด ๊ทผ์‚ฌ๋กœ ์ธํ•ด ์ผ๋ถ€ ๊ทผ์ ‘ ์ด์›ƒ์„ ๋†“์น  ์ˆ˜ ์žˆ์Œ
      • HNSW ์ธ๋ฑ์Šค๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ m, ef_search ๋“ฑ์„ ํ†ตํ•ด ์ •ํ™•๋„-์†๋„ ๊ท ํ˜•์„ ์žก์•„์•ผ ํ•˜๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’(ef_search=40)์œผ๋กœ ํ•„ํ„ฐ ์กฐ๊ฑด ์žˆ๋Š” ์งˆ์˜๋ฅผ ํ•˜๋ฉด ๊ฒฐ๊ณผ ๋ˆ„๋ฝ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด ๋†’์—ฌ์•ผ ํ•˜๋Š” ๋“ฑ ํŠœ๋‹ ํฌ์ธํŠธ๊ฐ€ ์กด์žฌ
    • ์ฆ‰, PGVector์˜ ์ธ๋ฑ์Šค๋Š” ์ž๋™ ์ตœ์ ํ™”๋ณด๋‹ค๋Š” ์ˆ˜๋™ ์กฐ์ •์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด ์‹ค๋ฌด ์ ์šฉ ์‹œ ๋ฒค์น˜๋งˆํฌ์™€ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ๊ฑฐ์ณ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋งž์ถ”๋Š” ๋…ธ๋ ฅ์ด ํ•„์š”
  3. ์ฐจ์› ๋ฐ ๋ฐ์ดํ„ฐ ํƒ€์ž… ํ•œ๊ณ„

    • ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด vector ํƒ€์ž…์€ ์ตœ๋Œ€ 2,000์ฐจ์›๊นŒ์ง€๋งŒ ์ธ๋ฑ์‹ฑ์ด ์ง€์›
      • ๋งค์šฐ ๊ณ ์ฐจ์›(์˜ˆ: 10,000์ฐจ์› ์ด์ƒ) ์ž„๋ฒ ๋”ฉ์˜ ๊ฒฝ์šฐ ๋ฐ”๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ฐจ์›์„ ์ถ•์†Œํ•˜๊ฑฐ๋‚˜ ์ ˆ๋ฐ˜์ •๋ฐ€๋„ ํƒ€์ž…(halfvec, ์ตœ๋Œ€ 4,000์ฐจ์›)์„ ๊ณ ๋ ค
    • ๋˜ํ•œ ๋ฒกํ„ฐ ์ปฌ๋Ÿผ์„ ์ •์˜ํ•  ๋•Œ ์ฐจ์›์„ ๊ณ ์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋งŒ์•ฝ ๋‹ค๋ฅธ ์ฐจ์›์˜ ์ž„๋ฒ ๋”ฉ์„ ํ•จ๊ป˜ ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋ฉด ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๊ฑฐ๋‚˜ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌ
    • ํ•œํŽธ PGVector์˜ ๋ฒกํ„ฐ ํƒ€์ž…์€ ๋ถ€๋™์†Œ์ˆ˜(float4) ์ •๋ฐ€๋„๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ, ๋ณด๋‹ค ๋†’์€ ์ •๋ฐ€๋„๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ (์˜ˆ: ๋งค์šฐ ๋ฏธ์„ธํ•œ ์œ ์‚ฌ๋„ ์ฐจ์ด๋ฅผ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•  ๋•Œ) ๊ธฐ๋ณธ ์ œ๊ณต ํƒ€์ž…์œผ๋กœ๋Š” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Œ
      • ์ด๋•Œ๋Š” ์ฐจ์„ ์ฑ…์œผ๋กœ PostgreSQL์˜ DOUBLE PRECISION[] ๋ฐฐ์—ด ๋“ฑ์— ์ž„๋ฒ ๋”ฉ์„ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜๋กœ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๋‚˜, ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ PGVector์˜ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•ด ์„ฑ๋Šฅ์ด ๊ฐ์†Œ
      • ์ •๋ฐ€๋„์™€ ์„ฑ๋Šฅ ์‚ฌ์ด์˜ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•จ
  4. ์ž์› ์‚ฌ์šฉ ๋ฐ ๊ธฐํƒ€

    • HNSW ์ธ๋ฑ์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋งŽ๊ณ  ๊ตฌ์ถ• ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Œ
      • ์ˆ˜๋ฐฑ๋งŒ ๋ฒกํ„ฐ์— ๋Œ€ํ•ด HNSW ์ƒ์„ฑ ์‹œ ์ˆ˜์‹ญ GB์˜ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ , maintenance_work_mem ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋†’์—ฌ์ค˜์•ผ ํ•จ
    • ๋ฐ˜๋ฉด IVFFlat์€ k-ํ‰๊ท  ํ•™์Šต์„ ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ธ๋ฑ์Šค ์ƒ์„ฑ ์‹œ CPU ๋ถ€ํ•˜๊ฐ€ ๋†’์„ ์ˆ˜ ์žˆ์Œ
      • ์ธ๋ฑ์Šค ํฌ๊ธฐ๋„ ๋ฐ์ดํ„ฐ์–‘์— ๋น„๋ก€ํ•˜์—ฌ ๋””์Šคํฌ๋ฅผ ์ฐจ์ง€ํ•˜๋ฏ€๋กœ ์ €์žฅ๊ณต๊ฐ„ ๊ณ„ํš์ด ํ•„์š”
    • PGVector๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ PostgreSQL ์‹ฑ๊ธ€ ๋…ธ๋“œ์— ์˜์กดํ•˜๋ฏ€๋กœ ์ˆ˜ํ‰์  ํ™•์žฅ(์ƒค๋”ฉ)์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ
    • ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ์…‹์„ ์—ฌ๋Ÿฌ ๋…ธ๋“œ๋กœ ๋ถ„์‚ฐํ•˜๋ ค๋ฉด Citus์™€ ๊ฐ™์€ ํ™•์žฅ์ด๋‚˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ ์ƒค๋”ฉ์„ ๊ฒ€ํ† ํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ ๋ฒกํ„ฐ ์œ ์‚ฌ๋„ ์งˆ์˜๋ฅผ ๋ถ„์‚ฐ ์‹คํ–‰ํ•˜๋Š” ๋กœ์ง์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ

4. ์ธ๋ฑ์Šค : HNSW vs IVFFlat

TL;DR

  • HNSW๋Š” ์ •ํ™•๋„ ๋†’๊ณ  ๊ฒ€์ƒ‰์ด ๋น ๋ฅด๋‚˜ ๋ฉ”๋ชจ๋ฆฌ/๊ตฌ์ถ•๋น„์šฉ์ด ํผ
  • IVFFlat์€ ๊ฐ€๋ฒผ์šด ๋Œ€์‹  ํŠœ๋‹ ๋‚œ์ด๋„๊ฐ€ ์žˆ๊ณ  ์ •ํ™•๋„๊ฐ€ ์•ฝ๊ฐ„ ๋‚ฎ์„ ์ˆ˜ ์žˆ์Œ
  • ๋‘˜ ๋‹ค ๋งค๊ฐœ๋ณ€์ˆ˜ ์กฐ์ •์œผ๋กœ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์—ฌ์ง€๊ฐ€ ํฌ๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ ๊ทœ๋ชจ์™€ ์‘๋‹ต ์†๋„ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๋ฅผ ์„ ํƒํ•˜๊ณ  ์‹คํ—˜์„ ํ†ตํ•ด ์ตœ์ ์˜ ์„ค์ •์„ ์ฐพ์•„๋‚ด๋Š” ๊ฒƒ์ด ์ค‘์š”

PGVector๋Š” ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ์ฃผ์š” ๊ทผ์‚ฌ ๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค

HNSW (Hierarchical Navigable Small World)
  • Hierarchical Navigable Small World๋ฅผ ๋‹ค์ธต์œผ๋กœ ๊ตฌ์ถ•ํ•˜์—ฌ ๊ทผ์ ‘ ์ด์›ƒ์„ ์ฐพ๋Š” ๋ฐฉ์‹
  • ๋†’์€ ๊ฒ€์ƒ‰ ์ •ํ™•๋„์™€ ๋‚ฎ์€ ์ง€์—ฐ์„ ์ œ๊ณตํ•˜๋ฉฐ, ์ฃผ์–ด์ง„ ์ž์› ๋‚ด์—์„œ IVFFlat๋ณด๋‹ค ์ „๋ฐ˜์ ์œผ๋กœ ์šฐ์ˆ˜ํ•œ ์†๋„-์ •ํ™•๋„ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋ฅผ ๋ณด์ž„
  • ํ•™์Šต ๋‹จ๊ณ„ ์—†์ด ๊ทธ๋ž˜ํ”„๋ฅผ ๊ตฌ์ถ•ํ•˜๋ฏ€๋กœ ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด๋„ ์ธ๋ฑ์Šค ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์ƒ์„ฑ ์ดํ›„์—๋„ ๋™์‹œ ์‚ฝ์ž…์ด๋‚˜ ์‚ญ์ œ/์—…๋ฐ์ดํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋™์  ์ธ๋ฑ์Šค
  • ๋‹ค๋งŒ ์ธ๋ฑ์Šค ๋นŒ๋“œ์— ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ํฐ ์ ์ด ๋‹จ์ 
  • ๋ฒกํ„ฐ ์ฐจ์›๊ณผ ๊ฑฐ๋ฆฌํ•จ์ˆ˜์— ๋งž๋Š” ์—ฐ์‚ฐ์ž ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•จ (์˜ˆ: vector_l2_ops, vector_ip_ops ๋“ฑ)
  • ํŠœ๋‹ ํŒŒ๋ผ๋ฏธํ„ฐ
    • M : ํ•˜๋‚˜์˜ ๋…ธ๋“œ๊ฐ€ ๊ฐ–๋Š” ์ด์›ƒ ๋…ธ๋“œ ๊ฐœ์ˆ˜๋กœ ์ถ”์ฒœ ๋ฒ”์œ„๋Š” 5~48
      • ๊ฐ’์ด ์ปค์งˆ์ˆ˜๋ก
        • ๋นŒ๋“œ ์‹œ๊ฐ„, ๊ฒ€์ƒ‰ ์‹œ๊ฐ„, ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€
        • ๊ทธ๋ž˜ํ”„ ํ’ˆ์งˆ, ์ •ํ™•๋„ ํ–ฅ์ƒ
    • ef_construction : ๋นŒ๋“œ ์‹œ ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ์ €์žฅํ•˜๋Š” ํ›„๋ณด ๋ฆฌ์ŠคํŠธ ํฌ๊ธฐ
      • ๊ฐ’์ด ์ปค์งˆ์ˆ˜๋ก
        • ๋นŒ๋“œ ์‹œ๊ฐ„ ์ฆ๊ฐ€
        • ๊ทธ๋ž˜ํ”„ ํ’ˆ์งˆ, ์ •ํ™•๋„ ํ–ฅ์ƒ, ๊ฒ€์ƒ‰ ์‹œ๊ฐ„ ๊ฐ์†Œ
    • ef : ๊ฒ€์ƒ‰ ์‹œ ๋ฐฉ๋ฌธํ•œ ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ์ €์žฅํ•ด๋†“๋Š” ๋™์  ํ
      • ํ•ด๋‹น ๊ฐ’ ๋งŒํผ์˜ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰
      • ๊ฒ€์ƒ‰ ๊ฐœ์ˆ˜์ธ K๋ณด๋‹ค ์ปค์•ผํ•จ
    • ๋ฐ์ดํ„ฐ ๊ฒฝํ–ฅ์„ฑ : ํด๋Ÿฌ์Šคํ„ฐ๋ง์ด ์–ด๋А์ •๋„ ๋˜์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ์ผ์ˆ˜๋ก ์‘๋‹ต ์†๋„ ๋น ๋ฅด๊ณ  ์žฌํ˜„์œจ ๋†’์Œ
IVFFlat (Inverted File Index)
  • ๋ฒกํ„ฐ๋“ค์„ ๋ฏธ๋ฆฌ ์—ฌ๋Ÿฌ ํด๋Ÿฌ์Šคํ„ฐ ๋ฆฌ์ŠคํŠธ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ๊ฒ€์ƒ‰ ์‹œ ์ผ๋ถ€ ๋ฆฌ์ŠคํŠธ๋งŒ ํƒ์ƒ‰
  • k-ํ‰๊ท  ๊ตฐ์ง‘ํ™”๋ฅผ ํ†ตํ•ด ๋ฒกํ„ฐ ๊ณต๊ฐ„์„ ๋ฏธ๋ฆฌ ๋ถ„ํ• ํ•˜๋ฏ€๋กœ ์ธ๋ฑ์Šค ์ƒ์„ฑ ์‹œ ์•ฝ๊ฐ„์˜ ํ•™์Šต ์‹œ๊ฐ„์ด ๋“ค์ง€๋งŒ, HNSW์— ๋น„ํ•ด ์ธ๋ฑ์Šค ์ƒ์„ฑ ์†๋„๊ฐ€ ๋น ๋ฅด๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ์ ์€ ์žฅ์ 
  • ๋Œ€์‹  ๊ฒ€์ƒ‰ ์ •ํ™•๋„๋ฅผ ๋†’์ด๋ ค๋ฉด ๋” ๋งŽ์€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ดํŽด๋ด์•ผ ํ•˜๋ฏ€๋กœ ๋™์ผ ์ˆ˜์ค€์˜ ์ •ํ™•๋„์—์„œ๋Š” HNSW๋ณด๋‹ค ๋А๋ฆด ์ˆ˜ ์žˆ์Œ
  • IVFFlat ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ๋ช‡ ๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ๋กœ ๋ถ„ํ• ํ• ์ง€(lists ๋งค๊ฐœ๋ณ€์ˆ˜) ์„ค์ •ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋ณดํ†ต ๋ฐ์ดํ„ฐ ๊ฑด์ˆ˜์˜ โˆšN ์ˆ˜์ค€์ด๋‚˜ N/1000 ์ˆ˜์ค€์œผ๋กœ ์‹œ์ž‘ํ•˜์—ฌ ์กฐ์ •
    • ๋ฆฌ์ŠคํŠธ ์ˆ˜๊ฐ€ ๋งŽ์„์ˆ˜๋ก ์ธ๋ฑ์Šค ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๊ณ  ๊ตฌ์ถ• ์‹œ๊ฐ„์ด ๋Š˜์ง€๋งŒ, ์ •ํ™•๋„๋Š” ๋†’์•„์งˆ ์ˆ˜ ์žˆ์Œ
  • ์ฟผ๋ฆฌ ์‹œ์—๋Š” SET ivfflat.probes = P๋กœ ํƒ์ƒ‰ํ•  ๋ฆฌ์ŠคํŠธ ๊ฐœ์ˆ˜(๊ธฐ๋ณธ 1๊ฐœ)๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, probes๋ฅผ ๋Š˜๋ฆด์ˆ˜๋ก ๋” ๋งŽ์€ ํ›„๋ณด๋ฅผ ํ™•์ธํ•˜์—ฌ ์ •ํ™•๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€๋งŒ ์†๋„๋Š” ๊ฐ์†Œ
    • ๊ทน๋‹จ์ ์œผ๋กœ probes๋ฅผ ๋ฆฌ์ŠคํŠธ ์ด ๊ฐœ์ˆ˜๋งŒํผ ์ฃผ๋ฉด ์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ค ๋’ค์ง€๋Š” ์…ˆ์ด ๋˜์–ด ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰๊ณผ ๋™์ผ (์ด ๊ฒฝ์šฐ Planner๋Š” ์ธ๋ฑ์Šค๋ฅผ ์“ฐ์ง€ ์•Š๊ณ  Sequential Scan์œผ๋กœ ๊ฐ„์ฃผ)
    • ์ ์ ˆํ•œ probes ๊ฐ’(์˜ˆ: ๊ธฐ๋ณธ๊ฐ’ 1์—์„œ ์‹œ์ž‘ํ•ด ์ •ํ™•๋„๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ์ ์ฐจ ์ฆ๊ฐ€)์„ ์ฐพ๋Š” ๊ฒƒ์ด ์ค‘์š”
  • IVFFlat๋„ ์ธ๋ฑ์Šค ์ƒ์„ฑ ์‹œ ๋ฒกํ„ฐ ์ฐจ์›์„ ์ง€์ •ํ•œ ์—ฐ์‚ฐ์ž ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ ์ƒ์„ฑ์€ HNSW์™€ ๋™์ผํ•œ DDL ๋ฌธ๋ฒ•์„ ๋”ฐ๋ฆ„
  • ์ฐธ๊ณ ๋กœ ์ดˆ๊ธฐ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์Œ“์ธ ํ›„ ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Œ
    • ๋„ˆ๋ฌด ์ ์€ ๋ฐ์ดํ„ฐ๋กœ ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ๊ฐ ๋ฆฌ์ŠคํŠธ์— ๋ฒกํ„ฐ๊ฐ€ ๊ณ ๋ฅด๊ฒŒ ๋ถ„ํฌ๋˜์ง€ ์•Š์•„ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ผ์ •๋Ÿ‰ ๋ˆ„์  ํ›„ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์žฌ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ

5. ์‹ค์Šต

pgvector & pgadmin ์ค€๋น„

pgvector๊ฐ€ ์„ค์น˜๋œ postgres์™€ pgadmin์„ ์ด์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ pgvector๋ฅผ ์‚ฌ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค

docker-compose.yml
services:
  postgres:
    image: pgvector/pgvector:pg17
    container_name: postgres-pgvector
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready -U postgres -d postgres
      interval: 10s
      timeout: 5s
      retries: 5
 
  # PGAdmin - PostgreSQL ๊ด€๋ฆฌ ์›น ์ธํ„ฐํŽ˜์ด์Šค
  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pgadmin
    depends_on:
      postgres:
        condition: service_healthy
    ports:
      - "5050:80"
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@example.com
      PGADMIN_DEFAULT_PASSWORD: admin
    volumes:
      - pgadmin_data:/var/lib/pgadmin
 
volumes:
  postgres_data:
  pgadmin_data:

http://localhost:5050์œผ๋กœ ์ ‘์†ํ•˜๋ฉด pgadmin ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋‚˜์˜ค๊ณ  docker-compose.yml์— ์žˆ๋Š” ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๋กœ๊ทธ์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค

๊ทธ ํ›„ ์ƒˆ ์„œ๋ฒ„ ์ถ”๊ฐ€๋ฅผ ์„ ํƒํ•˜๊ณ  [์ผ๋ฐ˜]์—์„œ ์ด๋ฆ„์€ โ€˜pgvector-testโ€™, [์—ฐ๊ฒฐ]์—์„œ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„/์ฃผ์†Œ๋Š” โ€˜postgres-pgvectorโ€™, ํฌํŠธ๋Š” โ€˜5432โ€™, ์ ‘์† ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค/์‚ฌ์šฉ์ž์ด๋ฆ„/๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ชจ๋‘ โ€˜postgresโ€™๋กœ ์„ค์ •ํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ postgreSQL๊ณผ ์—ฐ๊ฒฐ์ด ๋œ๋‹ค

ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋ฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
-- ================================
-- 0) ํ™•์žฅ ์„ค์น˜ ๋ฐ ์ค€๋น„
-- ================================
CREATE EXTENSION IF NOT EXISTS vector;
 
DROP TABLE IF EXISTS doc_vectors;
CREATE TABLE doc_vectors (
  id      SERIAL PRIMARY KEY,
  title   TEXT NOT NULL,
  tags    TEXT[],
  emb     VECTOR(3)  -- ์˜ˆ์‹œ๋ผ 3์ฐจ์›, ์‹ค์ œ์—์„  384/768/1536 ๋“ฑ
);
 
-- ================================
-- 1) ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
--    - ์„œ๋กœ ์œ ์‚ฌ/์ƒ์ดํ•œ ์ฃผ์ œ๋ฅผ ์„ž์–ด ๋ฐฐ์น˜
-- ================================
INSERT INTO doc_vectors (title, tags, emb) VALUES
  ('AI ๊ธฐ์ˆ  ์†Œ๊ฐœ',        ARRAY['ai','tech'],        '[0.10, 0.20, 0.30]'),
  ('๋จธ์‹ ๋Ÿฌ๋‹ ๊ฐœ์š”',       ARRAY['ai','ml'],          '[0.20, 0.10, 0.40]'),
  ('๋”ฅ๋Ÿฌ๋‹ ๊ธฐ์ดˆ',         ARRAY['ai','dl'],          '[0.12, 0.18, 0.28]'),
  ('์š”๋ฆฌ ๋ ˆ์‹œํ”ผ ๋ชจ์Œ',    ARRAY['food','recipe'],    '[0.90, 0.80, 0.70]'),
  ('๋ฒ ์ดํ‚น ์ž…๋ฌธ',         ARRAY['food','baking'],    '[0.85, 0.78, 0.69]'),
  ('์œ ๋Ÿฝ ์—ฌํ–‰ ๊ฐ€์ด๋“œ',    ARRAY['travel','guide'],   '[0.55, 0.20, 0.15]');
 
-- ๊ธฐ์ค€ ๋ฌธ์„œ id ํ™•์ธ์šฉ
SELECT id, title FROM doc_vectors ORDER BY id;
  • pgvector extension์„ ์„ค์น˜
  • vector(3) ์ž๋ฃŒํ˜•์œผ๋กœ 3์ฐจ์› ๋ฒกํ„ฐ ์ž๋ฃŒํ˜•์„ ์„ ์–ธ
  • listํ˜•ํƒœ์˜ ๋ฒกํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด vector ์ž๋ฃŒํ˜•์œผ๋กœ ์‚ฝ์ž…
L2 ๊ฑฐ๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
-- ================================
-- 2) L2 ๊ฑฐ๋ฆฌ (์œ ํด๋ฆฌ๋“œ) ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
--    ์—ฐ์‚ฐ์ž: <->  (์ž‘์„์ˆ˜๋ก ์œ ์‚ฌ)
-- ================================
 
-- 2-1) ์ฟผ๋ฆฌ ๋ฒกํ„ฐ๋กœ Topโ€‘3 ์œ ์‚ฌ ๋ฌธ์„œ
SELECT id, title, emb <-> '[0.15, 0.15, 0.30]'::vector AS l2_dist
FROM doc_vectors
ORDER BY l2_dist
LIMIT 3;
 
-- 2-2) ํŠน์ • ๋ฌธ์„œ(id=1)์™€ ์œ ์‚ฌํ•œ ๋ฌธ์„œ Topโ€‘3
SELECT id, title,
       emb <-> (SELECT emb FROM doc_vectors WHERE id = 1) AS l2_dist
FROM doc_vectors
WHERE id <> 1
ORDER BY l2_dist
LIMIT 3;
 
-- 2-3) ์ž„๊ณ„๊ฐ’ ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ (L2 ๊ฑฐ๋ฆฌ๊ฐ€ 0.25 ์ดํ•˜)
SELECT id, title
FROM doc_vectors
WHERE emb <-> '[0.15, 0.15, 0.30]'::vector <= 0.25
ORDER BY emb <-> '[0.15, 0.15, 0.30]'::vector;
  • ::vector๋ฅผ ์ด์šฉํ•ด์„œ listํ˜•ํƒœ์˜ ๊ฐ’์„ ๋ฒกํ„ฐ์ž๋ฃŒํ˜•์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ
Inner product๋ฅผ ํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
-- ================================
-- 3) ๋‚ด์ (Inner Product) ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
--    ์—ฐ์‚ฐ์ž: <#>  (์ฃผ์˜: "๋ถ€ํ˜ธ๊ฐ€ ๋ฐ˜๋Œ€์ธ ๋‚ด์ ๊ฐ’"์„ ๋ฐ˜ํ™˜)
--    ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ ์‹œ ๋‚ด์ ๊ฐ’์ด ํฐ(์œ ์‚ฌํ•œ) ์ˆœ์„œ์™€ ๋™์ผํ•œ ํšจ๊ณผ
-- ================================
 
-- 3-1) ์ฟผ๋ฆฌ ๋ฒกํ„ฐ๋กœ Topโ€‘3 (๋‚ด์  ๊ธฐ์ค€)
SELECT id, title,
       emb <#> '[0.15, 0.15, 0.30]'::vector AS neg_inner_product
FROM doc_vectors
ORDER BY neg_inner_product   -- ์˜ค๋ฆ„์ฐจ์ˆœ == ๋‚ด์  ํฐ ์ˆœ
LIMIT 3;
 
-- 3-2) ํŠน์ • ๋ฌธ์„œ(id=1) ๊ธฐ์ค€ Topโ€‘3 (๋‚ด์  ๊ธฐ์ค€)
SELECT id, title,
       emb <#> (SELECT emb FROM doc_vectors WHERE id = 1) AS neg_inner_product
FROM doc_vectors
WHERE id <> 1
ORDER BY neg_inner_product
LIMIT 3;
  • <#> ๋ฅผ ํ™œ์šฉํ•ด ๋‘ ๋ฒกํ„ฐ ๊ฐ„์˜ ๋‚ด์ ์„ ๊ตฌํ•˜๋ฉด ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๊ฐ’์ด ํผ
  • pgvector์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฒกํ„ฐ๊ฐ„ ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๊ฑฐ๋ฆฌ metric์ด ์ž‘๋„๋ก ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋Š” ์Œ์ˆ˜๋กœ ๋‚˜์˜ด
Cosine ๊ฑฐ๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
-- ================================
-- 4) ์ฝ”์‚ฌ์ธ ๊ฑฐ๋ฆฌ/์œ ์‚ฌ๋„ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ์˜ˆ์‹œ
--    ์—ฐ์‚ฐ์ž: <=>  (์ฝ”์‚ฌ์ธ "๊ฑฐ๋ฆฌ" = 1 - ์ฝ”์‚ฌ์ธ "์œ ์‚ฌ๋„")
--    -> ์ฝ”์‚ฌ์ธ ์œ ์‚ฌ๋„ = 1 - (emb <=> query)
-- ================================
 
-- 4-1) ์ฟผ๋ฆฌ ๋ฒกํ„ฐ๋กœ Topโ€‘3 (์ฝ”์‚ฌ์ธ)
SELECT id, title,
       emb <=> '[0.15, 0.15, 0.30]'::vector            AS cosine_distance,
       1 - (emb <=> '[0.15, 0.15, 0.30]'::vector)      AS cosine_similarity
FROM doc_vectors
ORDER BY cosine_distance
LIMIT 3;
 
-- 4-2) ํŠน์ • ๋ฌธ์„œ(id=1) ๊ธฐ์ค€ Topโ€‘3 (์ฝ”์‚ฌ์ธ)
SELECT id, title,
       emb <=> (SELECT emb FROM doc_vectors WHERE id = 1)           AS cosine_distance,
       1 - (emb <=> (SELECT emb FROM doc_vectors WHERE id = 1))     AS cosine_similarity
FROM doc_vectors
WHERE id <> 1
ORDER BY cosine_distance
LIMIT 3;
  • ๋‚ด์ ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๊ฐ’์ด 1์— ๊ฐ€๊น๊ธฐ ๋•Œ๋ฌธ์— 1์—์„œ ๊ฐ’์„ ๋นผ์„œ ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ์ž‘๊ฒŒ ํ‘œํ˜„
๋‹ค๋ฅธ ์†์„ฑ์˜ ํ•„ํ„ฐ๋ง๊ณผ ๊ฒฐํ•ฉ
-- ================================
-- 5) ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ•„ํ„ฐ + ์œ ์‚ฌ๋„ ๊ฒ€์ƒ‰ ๊ฒฐํ•ฉ
--    (์˜ˆ: ํƒœ๊ทธ์— 'ai' ํฌํ•จ ๋ฌธ์„œ ์ค‘์—์„œ๋งŒ ์ฝ”์‚ฌ์ธ Topโ€‘3)
-- ================================
SELECT id, title,
       1 - (emb <=> '[0.15, 0.15, 0.30]'::vector) AS cos_sim
FROM doc_vectors
WHERE 'ai' = ANY(tags)
ORDER BY emb <=> '[0.15, 0.15, 0.30]'::vector
LIMIT 3;
  • tags์— โ€˜aiโ€™๋ฅผ ํฌํ•จํ•˜๋Š” ์ฑ… ๋‚ด์—์„œ๋งŒ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Œ
ANN ์ธ๋ฑ์Šค ํ™•์ธ์šฉ ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋ฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
CREATE TABLE big_vectors (
    id      bigserial PRIMARY KEY,
    emb     vector(1532),
    payload text
);
 
CREATE OR REPLACE FUNCTION random_vector_1532()
RETURNS vector(1532)
AS $$
	SELECT array_agg((random() * 2 - 1)::real ORDER BY i)::vector(1532)
	FROM generate_series(1, 1532) AS g(i)
$$ LANGUAGE sql VOLATILE;
 
-- ๋ฐ์ดํ„ฐ ์‚ฝ์ž… (10๋งŒ ํ–‰ ์˜ˆ์‹œ, ํ•„์š”์‹œ ํ–‰ ์ˆ˜ ์กฐ์ •) : 25 secs 330 msec.
INSERT INTO big_vectors (emb, payload)
SELECT random_vector_1532(), md5(gs::text)
FROM generate_series(1, 100000) gs;
  • 1532 ์ฐจ์›์˜ ๋ฒกํ„ฐ๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ํ…Œ์ด๋ธ” ์ƒ์„ฑ
  • ๋žœ๋คํ•˜๊ฒŒ 1532 ์ฐจ์›์˜ ๋ฒกํ„ฐ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” UDF ์ •์˜
  • ์ •์˜ํ•œ UDF๋กœ 100,000๊ฐœ์˜ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
ANN ์ธ๋ฑ์Šค ์ƒ์„ฑ ์ „ Exact Matching ์„ฑ๋Šฅ ํ™•์ธ
-- ๋ถ„์„ ํ†ต๊ณ„ ์—…๋ฐ์ดํŠธ
VACUUM ANALYZE big_vectors;
 
-- ์ฟผ๋ฆฌ ๋ฒกํ„ฐ ๊ณ ์ •
DROP TABLE IF EXISTS qvec;
CREATE UNLOGGED TABLE qvec AS
SELECT random_vector_1532() AS q;
 
 
-- ์ธ๋ฑ์Šค ์—†์ด ์ •ํ™•ํƒ์ƒ‰ ์„ฑ๋Šฅ
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, emb <-> (SELECT q FROM qvec)
FROM big_vectors
ORDER BY emb <-> (SELECT q FROM qvec)
LIMIT 10;
  • VACUUM์œผ๋กœ dead tuple ์ •๋ฆฌํ•˜๊ณ  ANALYZE๋กœ big_vectors ํ…Œ์ด๋ธ”์˜ ํ†ต๊ณ„ ์ •๋ณด ์—…๋ฐ์ดํŠธ
  • ์ฟผ๋ฆฌ์— ์‚ฌ์šฉํ•  ๋ฒกํ„ฐ ์ƒ์„ฑํ•ด์„œ WAL์— ์ €์žฅ์•ˆ๋˜๋Š” UNLOGGED ํ…Œ์ด๋ธ”์— ์ €์žฅ
  • ์‚ฌ์ „์— ์ƒ์„ฑํ•œ ์ฟผ๋ฆฌ ๋ฒกํ„ฐ์™€ ์œ ์‚ฌ๋„ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ โ†’ โ€˜Parallel Seq Scanโ€™ ์ˆ˜ํ–‰
    ์ธ๋ฑ์Šค ์‚ฌ์šฉ X
    Limit  (cost=4167.07..4168.22 rows=10 width=16) (actual time=883.367..885.444 rows=10 loops=1)
      Buffers: shared hit=499279 read=101982 written=4883
      InitPlan 1
        ->  Seq Scan on qvec  (cost=0.00..23.60 rows=1360 width=32) (actual time=0.009..0.009 rows=1 loops=1)
              Buffers: shared hit=1
      ->  Gather Merge  (cost=4143.47..10908.23 rows=58824 width=16) (actual time=883.365..885.440 rows=10 loops=1)
            Workers Planned: 1
            Workers Launched: 1
            Buffers: shared hit=499279 read=101982 written=4883
            ->  Sort  (cost=3143.46..3290.52 rows=58824 width=16) (actual time=878.597..878.599 rows=8 loops=2)
                  Sort Key: ((big_vectors.emb <-> (InitPlan 1).col1))
                  Sort Method: top-N heapsort  Memory: 25kB
                  Buffers: shared hit=499278 read=101982 written=4883
                  Worker 0:  Sort Method: top-N heapsort  Memory: 25kB
                  ->  Parallel Seq Scan on big_vectors  (cost=0.00..1872.30 rows=58824 width=16) (actual time=0.249..869.867 rows=50000 loops=2)
                        Buffers: shared hit=499241 read=101982 written=4883
    Planning:
      Buffers: shared hit=4
    Planning Time: 0.169 ms
    Execution Time: 885.477 ms
HNSW ์ธ๋ฑ์Šค ์ƒ์„ฑ ๋ฐ ๋™์ผํ•œ ์ฟผ๋ฆฌ ์ˆ˜ํ–‰
-- HNSW ์ธ๋ฑ์Šค ์ƒ์„ฑ
DROP INDEX IF EXISTS idx_big_vectors_hnsw;
CREATE INDEX idx_big_vectors_hnsw
ON big_vectors USING hnsw (emb vector_l2_ops)
WITH (m = 16, ef_construction = 200);
 
ANALYZE big_vectors;
 
-- HNSW ์ฟผ๋ฆฌ (ef_search ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
SET hnsw.ef_search = 80;
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, emb <-> (SELECT q FROM qvec)
FROM big_vectors
ORDER BY emb <-> (SELECT q FROM qvec)
LIMIT 10;
  • ์ธ๋ฑ์Šค ์ƒ์„ฑ์— 12๋ถ„ 30์ดˆ ์ •๋„ ์†Œ์š”
    • ์ธ๋ฑ์Šค ์ƒ์„ฑ๊ณผ์ •์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ๋””์Šคํฌ ์ž„์‹œ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด์„œ ๊ณ„์† ์ง„ํ–‰ โ†’ NOTICE:ย  hnsw graph no longer fits into maintenance_work_mem after 9239 tuples
    • ์ธ๋ฑ์Šค ๋นŒ๋“œ ์†๋„๋Š” ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์™„์„ฑ๋œ ์ธ๋ฑ์Šค ์ž์ฒด์˜ ์„ฑ๋Šฅ์—๋Š” ํฐ ์˜ํ–ฅ ์—†์Œ
  • ์œ ์‚ฌ๋„ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ โ†’ HNSW ์ธ๋ฑ์Šค ์‚ฌ์šฉ
    HNSW index
    Limit  (cost=1169.23..1209.77 rows=10 width=16) (actual time=4.072..4.189 rows=10 loops=1)
      Buffers: shared hit=3247
      InitPlan 1
        ->  Seq Scan on qvec  (cost=0.00..23.60 rows=1360 width=32) (actual time=0.006..0.007 rows=1 loops=1)
              Buffers: shared hit=1
      ->  Index Scan using idx_big_vectors_hnsw on big_vectors  (cost=1145.63..406552.00 rows=100000 width=16) (actual time=4.071..4.186 rows=10 loops=1)
            Order By: (emb <-> (InitPlan 1).col1)
            Buffers: shared hit=3247
    Planning:
      Buffers: shared hit=1
    Planning Time: 0.068 ms
    Execution Time: 4.207 ms
IVFFlat ์ธ๋ฑ์Šค ์ƒ์„ฑ ๋ฐ ๋™์ผํ•œ ์ฟผ๋ฆฌ ์ˆ˜ํ–‰
-- ๊ธฐ์กด hnsw ์ธ๋ฑ์Šค ์ œ๊ฑฐ
DROP INDEX IF EXISTS idx_big_vectors_hnsw;
 
-- IVFFlat ์ธ๋ฑ์Šค ์ƒ์„ฑ
DROP INDEX IF EXISTS idx_big_vectors_ivf;
CREATE INDEX idx_big_vectors_ivf
ON big_vectors USING ivfflat (emb vector_l2_ops)
WITH (lists = 80);
 
ANALYZE big_vectors;
 
-- IVFFlat ์ฟผ๋ฆฌ (probes ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
SET ivfflat.probes = 10;
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, emb <-> (SELECT q FROM qvec)
FROM big_vectors
ORDER BY emb <-> (SELECT q FROM qvec)
LIMIT 10;
  • ์ธ๋ฑ์Šค๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ๋Š” hnsw ์ธ๋ฑ์Šค ์ œ๊ฑฐ
  • IVFFlat ์ธ๋ฑ์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ ๋ฐ”๋กœ Error โ†’ ERROR:ย  memory required is 506 MB, maintenance_work_mem is 64 MB
    • ์ธ๋ฑ์Šค ๋นŒ๋“œํ•  ๋™์•ˆ SET LOCAL maintenance_work_mem = '1GB';์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ ํ™•์žฅ
    • lists ๊ฐ’ ๋‚ฎ์ถฐ์„œ ๋ฉ”๋ชจ๋ฆฌ ์š”๊ตฌ๋Ÿ‰ ๊ฐ์†Œ
  • ์œ ์‚ฌ๋„ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ โ†’ IVFFlat ์ธ๋ฑ์Šค ์‚ฌ์šฉ
    IVFFlat index
    Limit  (cost=1254.35..1279.90 rows=10 width=16) (actual time=92.153..92.239 rows=10 loops=1)
      Buffers: shared hit=7490 read=39200
      InitPlan 1
        ->  Seq Scan on qvec  (cost=0.00..23.60 rows=1360 width=32) (actual time=0.005..0.006 rows=1 loops=1)
              Buffers: shared hit=1
      ->  Index Scan using idx_big_vectors_ivf on big_vectors  (cost=1230.75..256750.50 rows=100000 width=16) (actual time=92.151..92.236 rows=10 loops=1)
            Order By: (emb <-> (InitPlan 1).col1)
            Buffers: shared hit=7490 read=39200
    Planning:
      Buffers: shared hit=1
    Planning Time: 0.073 ms
    Execution Time: 92.257 ms

Footnotes

  1. ์—ฌ๋Ÿฌ worker process๊ฐ€ ๋™์‹œ์— ํ…Œ์ด๋ธ” ๋‚˜๋ˆ„์–ด ์ฝ๋Š” ๋ฐฉ์‹ โ†ฉ

  2. Write Ahead Log. ๋ณ€๊ฒฝ ๋กœ๊ทธ ์‹œ์Šคํ…œ์œผ๋กœ ์‹ค์ œ ๋ฐ์ดํ„ฐ ํŒŒ์ผ ์ˆ˜์ •ํ•˜๊ธฐ ์ „์— ๋จผ์ € ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๊ณ  ์ดํ›„ ๋ฐ์ดํ„ฐ ํŒŒ์ผ์— ๋ฐ˜์˜ํ•ด์„œ โ€˜์žฅ์•  ๋ณต๊ตฌ์™€ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅโ€™ โ†ฉ

  3. Point in Time Recovery. WAL ๋กœ๊ทธ๋ฅผ ์ด์šฉํ•ด ํŠน์ • ์‹œ์ ์œผ๋กœ DB ๋ณต๊ตฌํ•˜๋Š” ๊ฒƒ โ†ฉ

  4. Primary์—์„œ Standby ์„œ๋ฒ„ ๊ฐ„์— ์‹ค์‹œ๊ฐ„์œผ๋กœ WAL ๋กœ๊ทธ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋ณต์ œํ•˜๋Š” ๋ฐฉ์‹ โ†ฉ