ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐Ÿ“˜ Next.js + Vercel ํ™˜๊ฒฝ์—์„œ ํ•œ๊ธ€ ๊ฒ€์ƒ‰ ๊ตฌํ˜„๊ธฐ: ์‚ฝ์งˆ๊ธฐ๋ถ€ํ„ฐ ์ง์ ‘ bigram ๊ตฌํ˜„๊นŒ์ง€

Next.js + Vercel ํ™˜๊ฒฝ์—์„œ ํ•œ๊ธ€ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„์ด ์˜์™ธ๋กœ ๊ณจ์น˜ ์•„ํ”ˆ ์ผ์ด์—ˆ๊ณ  ์ด๋ฅผ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

 

1๏ธโƒฃ LIKE ๊ฒ€์ƒ‰? ๊ฐ„๋‹จํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์— ๋ถˆ์•ˆ ์š”์†Œ

์ฒ˜์Œ์—” ๋ˆ„๊ตฌ๋‚˜ WHERE title LIKE '%๊ฒ€์ƒ‰์–ด%'๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
๊ฐ„๋‹จํ•˜์ฃ . ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ๋ชปํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ ํ™• ๋А๋ ค์ง
  • ์ „์ฒด ์Šค์บ”์ด ๋ฐœ์ƒํ•ด ๋น„์šฉ์ด ๋น„์Œˆ
  • ๋‹จ์ˆœ ํฌํ•จ ๊ฒ€์ƒ‰์ด๋ผ ์˜๋ฏธ ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ๋ถˆ๊ฐ€

๊ทธ๋ž˜์„œ ๋ฐ”๋กœ ํฌ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค.

 

2๏ธโƒฃ PostgreSQL tsvector? …ํ•œ๊ธ€ ํ˜•ํƒœ์†Œ ๋ถ„์„์€ ๋ฏธ์ง€์› ๐Ÿ˜ข

PostgreSQL์˜ tsvector + to_tsvector ์กฐํ•ฉ์€ ํ’€ํ…์ŠคํŠธ ๊ฒ€์ƒ‰์„ ์œ„ํ•ด ๋งค์šฐ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
์˜ˆ์‹œ:

SELECT * FROM posts WHERE to_tsvector('english', title) @@ plainto_tsquery('english', 'search');
 

ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” ํ•œ๊ธ€์ž…๋‹ˆ๋‹ค. PostgreSQL ๊ธฐ๋ณธ ์„ค์ •์—์„  ์˜์–ด, ํ”„๋ž‘์Šค์–ด ๋“ฑ์€ ์ง€์›ํ•˜์ง€๋งŒ ํ•œ๊ตญ์–ด๋Š” ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ๊ฐ€ ์—†์–ด์„œ ์˜๋ฏธ ๋‹จ์œ„๋กœ ์ชผ๊ฐค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ tsvector๋ฅผ ๊ทธ๋Œ€๋กœ ์“ธ ์ˆ˜ ์—†๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์ฃ .

 

tsvector?

๊ฐ„๋‹จํžˆ ๋งํ•ด tsvector๋Š” ๊ฒ€์ƒ‰์„ ๋น ๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•œ ํ…์ŠคํŠธ ์ธ๋ฑ์Šค ํฌ๋งท์ž…๋‹ˆ๋‹ค.
๋‹จ์–ด ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์„œ ์ธ๋ฑ์‹ฑํ•˜๊ณ , tsquery๋กœ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

 

3๏ธโƒฃ ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ? → Vercel์—์„œ ๋ง‰ํž˜

์—ฌ๋Ÿฌ ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ๋ฅผ ํ™œ์šฉํ•˜๋ ค ํ–ˆ์ง€๋งŒ, Vercel์€ ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ์ด๋ผ:

  • ๋ณ„๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜
  • ์ž๋ฐ”๋‚˜ C++ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Vercel์€ ๋ฌด์กฐ๊ฑด ๋น ๋ฅด๊ณ  ์งง๊ฒŒ ๋๋‚˜๋Š” ํ•จ์ˆ˜ ์ค‘์‹ฌ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ ๋•Œ๋ฌธ์—, ๋ณ„๋„ ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ๋Š” ์• ์ดˆ์— ๊ตฌ์กฐ์ ์œผ๋กœ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

 

4๏ธโƒฃ ETRI ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ ์‚ฌ์šฉ? → IP ์ฐจ๋‹จ๋จ ๐Ÿ˜ญ

๋‹ค์Œ ์‹œ๋„๋กœ ETRI ๊ณต๊ฐœ API๋ฅผ ํ™œ์šฉํ–ˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. (https://aiopen.etri.re.kr/)

  • ์„œ๋ฒ„๋ฆฌ์Šค๋Š” ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„ IP๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ตฌ์กฐ
  • ์ผ์ • ํšŸ์ˆ˜ ์ดˆ๊ณผ๋˜๋ฉด "๋‹ค์ค‘ IP ์ ‘๊ทผ์œผ๋กœ ์ธํ•œ ์ฐจ๋‹จ" ๋ฐœ์ƒ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ETRI API๋„ ์ง€์†์ ์œผ๋กœ ์“ธ ์ˆ˜ ์—†์Œ

 

5๏ธโƒฃ pg_bigm ํ™•์žฅ ๋ชจ๋“ˆ? → Supabase์—์„œ ๋ฏธ์ง€์›

PostgreSQL์—๋Š” pg_bigm์ด๋ผ๋Š” ๊ฐ•๋ ฅํ•œ Bigram ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰ ํ™•์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•œ๊ธ€์ฒ˜๋Ÿผ ๊ณต๋ฐฑ ์—†์ด ๋ถ™์–ด ์žˆ๋Š” ์–ธ์–ด์—์„œ ์œ ์šฉํ•˜์ฃ .

ํ•˜์ง€๋งŒ Supabase์—์„œ๋Š” ์•„์ง pg_bigm ํ™•์žฅ์„ ๊ณต์‹ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์„ค์น˜ํ•˜๋ ค๋ฉด ์ปค์Šคํ…€ ์„œ๋ฒ„๋ฅผ ์จ์•ผ ํ•˜๊ณ , ๊ทธ๊ฑด Supabase๋ฅผ ์“ฐ๋Š” ์ด์œ  ์ž์ฒด๋ฅผ ํ๋ฆฌ๊ฒŒ ๋งŒ๋“ค์ฃ .

 

Bigram?

Bigram์€ ๋ฌธ์ž์—ด์„ ๋‘ ๊ธ€์ž์”ฉ ๋Š์–ด์„œ ๋ถ„์„ํ•˜๋Š” ๋ฐฉ์‹

 

โœ… ์ตœ์ข… ํ•ด๊ฒฐ์ฑ…: ์ง์ ‘ Bigram + tsvector ์กฐํ•ฉ ๊ตฌํ˜„

๊ฒฐ๊ตญ ์„ ํƒํ•œ ๋ฐฉ๋ฒ•์€ ์ง์ ‘ Bigram์œผ๋กœ ์ชผ๊ฐœ์„œ tsvector ํ˜•ํƒœ๋กœ ์ €์žฅํ•˜๊ณ , ์ด๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

// ์˜ˆ: "ํ•œ๊ตญ์–ด๊ฒ€์ƒ‰" → ["ํ•œ๊ตญ", "๊ตญ์–ด", "์–ด๊ฒ€", "๊ฒ€์ƒ‰"]
function toBigram(str: string): string[] {
  const grams = [];
  for (let i = 0; i < str.length - 1; i++) {
    grams.push(str.slice(i, i + 2));
  }
  return grams;
}

๊ทธ๋ฆฌ๊ณ  ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฏธ๋ฆฌ tsvector ํƒ€์ž… ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋ณ„๋„ ์ปฌ๋Ÿผ์— ์ €์žฅํ•ด๋‘๊ณ , ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๋„ bigram ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด tsquery๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. 

 

+ ์ปฌ๋Ÿผ์€ tsvector ํƒ€์ž…์ด์–ด์•ผ ํ•˜๊ณ , gin ์ธ๋ฑ์Šค๋ฅผ ๊ฑธ์–ด์•ผ ์„ฑ๋Šฅ์ƒ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๋งˆ๋ฌด๋ฆฌ

Next.js + Vercel + Supabase ์กฐํ•ฉ์—์„œ ํ•œ๊ธ€ ๊ฒ€์ƒ‰์„ ์ œ๋Œ€๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์‚ฝ์งˆ๊ธฐ๋ฅผ ์ •๋ฆฌํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

  • LIKE๋Š” ์„ฑ๋Šฅ์ƒ ํ•œ๊ณ„
  • PostgreSQL ๊ธฐ๋ณธ tsvector๋Š” ํ•œ๊ธ€ ๋ฏธ์ง€์›
  • ์™ธ๋ถ€ ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ/์„œ๋น„์Šค๋Š” ์„œ๋ฒ„๋ฆฌ์Šค์—์„œ ์‚ฌ์šฉ์ด ์–ด๋ ค์›€
  • ๊ทธ๋ž˜์„œ ๊ฒฐ๊ตญ Bigram + tsvector ๋ฐฉ์‹์œผ๋กœ ์ง์ ‘ ํ•ด๊ฒฐ

๋น„์Šทํ•œ ํ™˜๊ฒฝ์—์„œ ๊ณ ๋ฏผ ์ค‘์ด๋ผ๋ฉด, ์ด ๊ธ€์ด ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•
๋Œ“๊ธ€