ํ๋ก์ ํธ์์ ์ง์ญ์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ธ๊ตฌ์ง ๊ฒ์๊ธ์ ๋ฑ๋กํ๊ณ ๊ฒ์ํ๋ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ฒ ๋์๋ค.
์ด ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๊ธฐ ์ํด ์ค๊ณ์ ๋ง์ ๊ณ ๋ฏผ์ ํ๊ณ , ๊ตฌํ์ ๋ง์ ์๊ฐ์ ํฌ์ํ๊ฒ ๋์๋ค. ๊ทธ ๊ณผ์ ์ ๋์ง์ด๋ณด๊ณ ๊ณต์ ํ๊ณ ์ ํ๋ค!
๊ตฌํ์ ์ํด ๋น์ทํ๊ฒ ๋๋ค ๊ธฐ๋ฐ์ ์๋น์ค(๋น๊ทผ๋ง์ผ, ๋ฐฐ๋ฏผ..)์์ ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ๋ง์ด ์ฐพ์๋ดค์๋ค. ์ ํํ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง๋ ์ ์ ์์์ง๋ง, ๋ค๋ฅธ ์ฌ๋๋ค์ ๋น๊ทผ๋ง์ผ ํด๋ก ์ฝ๋ฉ๊ณผ ์ฌ๋ฌ ํ ํฌ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ์ฌ ๋๋ฆ๋๋ก ๋ด ์์ค์ ๋ง๊ฒ ํด๋น ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์๋ค.
๊ธฐ๋ฅ ์๊ฐ
๊ตฌ์ธ๊ตฌ์ง ๊ฒ์๊ธ ๋ฑ๋ก
- ๊ฒ์๊ธ ์์ฑ ์, ๊ตฌ์ธ๊ตฌ์ง์ ์์ธ ์กฐ๊ฑด๊ณผ ๊ฑฐ์ ์ง์ญ(ex. ์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ ์ญ์ผ๋)์ ์ ๋ ฅํ๋ค.
๊ตฌ์ธ๊ตฌ์ง ๊ฒ์๊ธ ๊ฒ์
- ๊ฒ์๊ธ ๊ฒ์ ์, ๊ฑฐ์ ์ง์ญ(ex. ์์ธํน๋ณ์ ๊ฐ๋จ๊ตฌ ์ญ์ผ๋)์ ์ ํํ๊ณ , ๊ทธ ๋ฐ๊ฒฝ(nkm)๋ฅผ ์ ํํ ์ ์๋ค.
์ ์ฌ ์๋น์ค ๋ถ์
๊ฒฐ๊ตญ ๋ด๊ฐ ๊ตฌํํด์ผ ํ๋ ๊ธฐ๋ฅ์ ๋๋ค ๊ธฐ๋ฐ์ ์ค๊ณ ๋ฌผํ ๊ฑฐ๋ ์๋น์ค์ธ '๋น๊ทผ๋ง์ผ'๊ณผ ์ ์ฌํ๋ค. ๋น๊ทผ๋ง์ผ์ GPS๋ก ์ธ์ฆ๋ ์ฌ์ฉ์์ ๋๋ค ์ฃผ๋ณ์ ์ค๊ณ ๊ฒ์๊ธ์ ๋ณด์ฌ์ค๋ค.
- ๋๋ค ๋ฒ์(๊ฐ๊น์ด ๋๋ค~๋จผ ๋๋ค)๋ฅผ ๋ณ๊ฒฝํ๋ฉด, ํ ํ๋ฉด์ ๋ณด์ฌ์ง๋ ๊ฒ์๊ธ์ ๋ฒ์๊ฐ ๋ฌ๋ผ์ง๋ค.
- ๋๋ค์ ๋ฒ์๋ ๊ฐ๊น์ด ๋๋ค๋ถํฐ ๋จผ ๋๋ค๊น์ง 4๋จ๊ณ๋ก ์ค์ ํ ์ ์๋ค.
- ๋จ๊ณ ๋ณ ๋๋ค๊ฐ ์ ํด์ ธ ์๋ค.
- ๋๋ค๋ ํ์ ๋์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค.
๋๋ค๋ฅผ ์ด๋ป๊ฒ ๋ค๋ฃฐ๊น?
1. ๋๋ค ๋ถ๋ฅ ์ฒด๊ณ : ๋ฒ์ ๋๊ณผ ํ์ ๋
์ฐ์ , ์ ๊ตญ์ ๋ชจ๋ ๋๋ค๋ฅผ ์์๋ด์ผ ํ๋ค. ์ฐ๋ฆฌ๋๋ผ์์ ๋๋ค๋ฅผ ๋ถ๋ฅํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ 2๊ฐ์ง๊ฐ ์๋ค.
๋ฒ์ ๋
- ๋ฒ๋ฅ ๋ก ์ง์ ํ ๊ณ ์ ์ง๋ช . ๋ฒ์ ๋ฌธ์์ ์ฌ์ฉํ๋ค.
- ๋ช ์นญ ๋ณ๋์ด ๊ฑฐ์ ์๋ค.
ํ์ ๋
- ํ์ ํธ์๋ฅผ ์ํด ์ค์ ํ ๊ตฌ์ญ. ํ์ ๋๋ง๋ค ์ฃผ๋ฏผ์ผํฐ๊ฐ ์๋ค.
- ์ฃผ๋ฏผ ์์ ์ฆ๊ฐ์ ๋ฐ๋ผ ์์๋ก ์ค์น, ํ์ง๋ ์๋ ์๋ค.
๋ฒ์ ๋๊ณผ ํ์ ๋์ ์ฐจ์ด๋ ์ด๋ฆ์ ๋ณด๋ฉด ์ ์ ์๋ค. ์์ ์ฒจ๋ถ๋ ์ด๋ฏธ์ง๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด, ์๋ฅผ ๋ค์ด, ์์ธ ํน๋ณ์ ์ข ๋ก๊ตฌ์ ๋ฒ์ ๋์ผ๋ก ์ฒญ์ด๋, ํจ์๋ ๋ฑ์ด ์๋ค. ํ์ง๋ง, ํ์ ๋์ผ๋ก๋ ๋ช ์นญ์ด ์ฒญ์ดํจ์๋์ผ๋ก ํตํฉ๋์ด ์๋ค.
์กํ๊ตฌ์ฒ๋ผ ์ธ๊ตฌ๊ฐ ๋ง์ ๋ฒ์ ๋์ด๋ผ๋ฉด ํ ๋ฒ์ ๋์ ํ์ ๋์ด ์ฌ๋ฌ ๊ฐ ์๊ธธ ์๋ ์๋ค. ๋ฐ๋๋ก ์ธ๊ตฌ๊ฐ ์ ์ผ๋ฉด ๋ฒ์ ๋ ์ฌ๋ฌ๊ฐ๋ฅผ ํ๋์ ํ์ ๋์ผ๋ก ๋ฌถ์ ์๋ ์๋ค.
๋ฐ๋ผ์, ์ด๋ค ๋ถ๋ฅ ์ฒด๊ณ๋ฅผ ์ฐ๋์ง์ ๋ฐ๋ผ ๋๋ค ๋ถ๋ฅ์ ๊ทผ์ฒ ๋๋ค์ ๋ฒ์๊ฐ ๋ฌ๋ผ์ง๊ฒ ๋๋ค.
2. ๋ฒ์ ๋ ์ ํ ์ด์
์ด์ ๋ถํฐ ํ๋ก ํธ์๋์์ ๋ค๋ฅธ ๊ธฐ๋ฅ์ ํ๋ฉด์ ๊ตฌํํ๋ฉด์ ํ์ ๋ ์ฒด๊ณ๋ฅผ ์ฐ๊ณ ์์๋ค. ๊ทธ๋์ ๋ฐฑ์๋์์๋ ํ์ ๋ ์ฒด๊ณ๋ฅผ ์ฐ๊ธฐ๋ก ํ๋ค.
ํ์ง๋ง, ํ์ ๋ ์ฒด๊ณ๋ก ๊ตฌํ ์ค์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๊ฒฐ๊ตญ ๊ทธ๋์ ๋ฒ์ ๋ ์ฒด๊ณ๋ก ๋ฐ๊พธ๊ฒ ๋์๋ค.
1) ์นด์นด์ค๋งต API ๊ฒ์ ๊ณผ์ ์์ ์๋ฌ
๋ค์์ ์ค๋ช ํ๊ฒ ์ง๋ง, ์์ ๋ก ์ป๊ฒ ๋ ๋ชจ๋ ๋๋ค์ ์ขํ๊ฐ์ ์ป๊ธฐ ์ํด ์นด์นด์ค๋งต API๋ฅผ ์ฌ์ฉํ๊ฒ ๋์๋ค. ํ์ง๋ง, ์์ ๋ฐ์ดํฐ์ ์นด์นด์ค๋งต ์์ ํ์ ๋๊ณผ ๋ช ์นญ์ด ๋ค๋ฅธ ๊ฒฝ์ฐ๊ฐ ์์ด ๊ฒ์์ด ์ ๋์๋ค.
ex)
์์ ๋ฐ์ดํฐ ์ - ์์ธ ์ค๋๊ตฌ ๋ฉด๋ชฉ์ 3.8๋
์นด์นด์ค ์ง๋ ์ - ์์ธ ์ค๋๊ตฌ ๋ฉด๋ชฉ 3.8๋
2) ์ ์ง๋ณด์ ์ธก๋ฉด์์ ์ ๋ฆฌ
ํ์ ๋์ ๋ฌธ์ ์ ์ ํ์ ์ ํธ์๋ฅผ ์ํด ์ธ๊ตฌ์๋ก ๋ช ์นญ๊ณผ ์์ญ์ ์ ํ๊ธฐ ๋๋ฌธ์ ๋ณ๋์ด ์ฆ๋ค๋ ๊ฒ์ด๋ค. ์ ์ง๋ณด์์ ์๊ฐํ๋ค๋ฉด ๋ช ์นญ ๋ณ๋์ด ๊ฑฐ์ ์๋ ๋ฒ์ ๋์ด ์ ๋ฆฌํ๋ค.
์ฐธ๊ณ ) ๋ฐฐ๋ฏผ์์๋ ์ง๋ฆฌ ๊ด๋ฆฌ ์ฒด๊ณ๋ฅผ ํ์ ๋์์ ๋ฒ์ ๋์ผ๋ก ์ ํํ๋ ์ด์ผ๊ธฐ๊ฐ ์๋ค. ํ์ ๋ ๋ฌธ์ ํด๊ฒฐํ๋ ค๊ณ ๊ฒ์ํ๋ค๊ฐ ๋ฐ๊ฒฌํ๋ค!
3. ๊ทผ์ฒ ๋๋ค๋ฅผ ์ด๋ป๊ฒ ์ ์ ์์๊น?
์ฐ์ , ๋ฒ์ ๋์ฝ๋์ ๊ท์น์ด ์๋์ง ์ดํด๋ดค๋ค. ๊ทผ์ฒ ๋๋ค ๊ฐ ์ฝ๋๊ฐ ์ ์ฌํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ด๋ค.
ํ์ง๋ง, ๋ฒ์ ๋์ฝ๋์ ์ฐจ์ด๊ฐ ์๋ค๊ณ ํด์ ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ๊น์ด ๋๋ค๋ ์๋๋ค. ๊ฒฝ๊ธฐ๋ ์ฑ๋จ์์ ์์ ๋ถ์๋ ์ฝ๋์ ์ซ์๊ฐ ์๋ก ๊ฐ๊น์ง๋ง, ์ค์ ๋ก ๊ฑฐ๋ฆฌ๋ ๊ฒฝ๊ธฐ ๋จ๋ถ์ ๋ถ๋ถ๋ก ์์ฒญ๋ ์ฐจ์ด๊ฐ ์๋ค.
๊ทธ๋ ๋ค๋ฉด, ๋๋ค ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ์ฌ ๊ทผ์ฒ ๋๋ค๋ฅผ ๊ตฌํด์ผ ํ๋ค.
๊ฒฐ๊ตญ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๋ ค๋ฉด ๊ฐ ๋๋ค ๋ณ ์ขํ๋ฅผ ์์์ผ ํ๋ค.
๋๋ค ๋ณ ์ขํ ๊ตฌํ๊ธฐ
1. ์ ์ฒด ๋๋ค ๋ฐ์ดํฐ ๊ตฌํ๊ธฐ
์ ๊ตญ์ ๋ฒ์ ๋ ๋ฐ์ดํฐ๋ ํ์ ์์ ๋ถ ์๋ฃ๋ฅผ ํตํด์ xlsx(์์ ) ํ์ผ๋ก ์ป์ ์ ์์๋ค.
xlsx ํ์ผ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ ์ ์๋ Python ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ์ ๊ตญ์ ๋ชจ๋ ๋๋ค์ ์๋์ฝ๋, ์๋๋ช , ์๊ตฐ๊ตฌ๋ช , ์๋ฉด๋๋ช ์ ์ถ์ถํด DB์ ์ ์ฅํ๋ค.
์์ธํ ๊ณผ์ ์ ์๋ ํฌ์คํธ์์ ๋ณด๋ฉด ๋๋ค.
https://programmingiraffe.tistory.com/184
2. ์ ์ฒด ๋๋ค ์ขํ ๊ตฌํ๊ธฐ
ํ์ง๋ง, ๋ฒ์ ๋ ๋ณ ์ขํ๊ฐ์ ๋ฐ๋ก ํ์ผ๋ก ์ป๊ธฐ ํ๋ค์๊ณ , ์๋ค ํ๋๋ผ๋ ํ๋์ ์ขํ(์๋, ๊ฒฝ๋)๋ก ์ถ์ถํ๊ธฐ๊ฐ ์ด๋ ค์ ๋ค.
๊ทธ๋์ ์นด์นด์ค๋งต API๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ ๋์ ์ง๋์์ ๊ฒ์ํด ์ขํ(์๋, ๊ฒฝ๋)๋ก ๋ณํํ๋๋ก ํ๋ค. ์ด ๋ถ๋ถ ๋ํ, ๋ฒ์ ๋ ์ถ์ถํ๋ ๋ถ๋ถ๊ณผ ํจ๊ป Python์ผ๋ก ์นด์นด์ค API์ ํต์ ํด์ ์๋, ๊ฒฝ๋ ๊ฐ์ ๊ฐ์ ธ์ DB์ ์ ์ฅํ๋๋ก ํ๋ค.
์์ธํ ๊ณผ์ ์ ์๋ ํฌ์คํธ์์ ๋ณด๋ฉด ๋๋ค.
https://programmingiraffe.tistory.com/185
๋ฐ๊ฒฝ nKm ์ด๋ด ๋๋ค ๊ฒ์ํ๊ธฐ
์ฌ์ฉ์์ ๊ฑฐ์ ์ง์ญ ๊ทผ์ฒ์ ๊ฒ์๊ธ์ ๊ฒ์ํ๊ธฐ ์ํด์ ์ฐ์ ๊ฑฐ์ ์ง์ญ์ผ๋ก๋ถํฐ nKm ์ด๋ด์ ์๋ ๋๋ค๋ฅผ ์์์ผ ํ๋ค.
DB์์ ์ง์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํด ๊ฒ์ํ๋ ๋ฐฉ๋ฒ๋ ์๊ณ , ์ธ๋ถ API๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ ์์๋ค. ์ธ๋ถ API๋ฅผ ์ฌ์ฉํ์ ๋, ์ํ ์๊ฐ์ด 8์ด๋ก ์์ฒญ ์ค๋ ๊ฑธ๋ ค์ ์ง์ DB์์ ๊ณ์ฐ์ ํ๊ธฐ๋ก ํ๋ค.
DB์ ์ ์ฅ๋ ๋ฒ์ ๋ ๋ฐ์ดํฐ๊ฐ ์ฝ 5000๊ฐ์ด๊ธฐ ๋๋ฌธ์ ๊ฒ์ ์๊ฐ์ ์ค์ฌ์ผ ํ์๋ค. ๋ชจ๋ ์ง์ญ์ ๋ฐ์ดํฐ๋ฅผ ์ํํ๋ฉด์ ๊ฑฐ์ ์ง์ญ๊ณผ ํด๋น ์ง์ญ์ ์ขํ์ ๊ฑฐ๋ฆฌ๊ฐ ๋ช km์ธ์ง ๊ณ์ฐํ๋ค๋ ๊ฒ์ ์๊ฐ์ด ๊ฝค ๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฐ ๋ฒ์ ๋ ๋ณ๋ก ๊ทผ์ฒ ๋๋ค๋ฅผ ๋ฏธ๋ฆฌ ๊ณ์ฐ์ ํด DB์ ์ ์ฅํด๋๊ณ ์กฐํํ๋ ๋ฐฉ์๋ ์๊ฐํด๋ดค์๋ค. ์ขํ๊ฐ ๊ณ ์ ๋์ด ์์ง ์๊ณ nKm๋ก ์ ํํ๋ ๋ฐฉ์์ด๋ผ์ ๋งค๋ฒ ๊ฒ์์ ํ๊ธฐ๋ก ํ๋ค. ๋ง์ฝ, ๋ฐ๊ฒฝ์ธ km๊ฐ ๊ณ ์ ์ด ๋์ด์๋ค๋ฉด, ๋ฏธ๋ฆฌ ์ฌ์ ์์ ์ ํตํด ๊ฐ ๋๋ค ๋ณ ๊ทผ์ฒ ๋๋ค๋ฅผ DB์ ์ ์ฅํ์ ๊ฒ์ด๋ค.
์๊ฐ์ ์ค์ผ ์ ์๋ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ค๊ฐ Bounding Box๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ ์๊ฒ ๋์๋ค.
Bounding Box
- ํน์ ๋ฐ๊ฒฝ ๋ด์ ์ขํ๋ฅผ ์ฐพ์ ๋, ๋ฐ๊ฒฝ์ ํฌํจํ๋ ์ฌ๊ฐํ์ธ Bounding Box๋ฅผ ๊ณ์ฐํ์ฌ ๋๋ต์ ์ธ ๋ฒ์๋ฅผ ์ขํ๋ ๋ฐฉ์์ด๋ค.
- ์ํ ๊ณต์์ ์ด์ฉํ์ฌ ๋ฐ๊ฒฝ์ ์ฌ๊ฐํ์ ๊ตฌํ ์ ์๋ค.
@Component
public class GeoUtils {
private static final double EARTH_RADIUS = 6371.01; // Earth's radius in km
public double[] getBoundingBox(double latitude, double longitude, double distance) {
double radLat = Math.toRadians(latitude);
double radLon = Math.toRadians(longitude);
double radDist = distance / EARTH_RADIUS;
double minLat = radLat - radDist;
double maxLat = radLat + radDist;
double minLon, maxLon;
if (minLat > -Math.PI / 2 && maxLat < Math.PI / 2) {
double deltaLon = Math.asin(Math.sin(radDist) / Math.cos(radLat));
minLon = radLon - deltaLon;
if (minLon < -Math.PI) {
minLon += 2 * Math.PI;
}
maxLon = radLon + deltaLon;
if (maxLon > Math.PI) {
maxLon -= 2 * Math.PI;
}
} else {
minLat = Math.max(minLat, -Math.PI / 2);
maxLat = Math.min(maxLat, Math.PI / 2);
minLon = -Math.PI;
maxLon = Math.PI;
}
return new double[]{Math.toDegrees(minLat), Math.toDegrees(minLon), Math.toDegrees(maxLat), Math.toDegrees(maxLon)};
}
}
์ฟผ๋ฆฌ๋ก ๊ฑฐ๋ฆฌ ๊ณ์ฐํ๊ธฐ
- Bounding Box๋ก ๊ณ์ฐํ ์ขํ ๋ด์ ์๋ ์ง์ญ์ ์ฐพ๊ณ , ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ ํตํด ๋ฐ๊ฒฝ ๋ด์ ์๋ ์ขํ์ธ์ง ํ์ธํ๋ค.
public interface AddressRepository extends JpaRepository<Address, String> {
@Query(
value = "SELECT address_code " +
"FROM address " +
"WHERE lat BETWEEN :minLat AND :maxLat " +
"AND lng BETWEEN :minLon AND :maxLon " +
"AND ST_Distance_Sphere(POINT(:lng, :lat), POINT(lng, lat)) <= (:distance * 1000) ",
nativeQuery = true
)
List<String> getNearbyAddressCodeByBoundingBox(@Param("lat") double lat,
@Param("lng") double lng,
@Param("minLat") double minLat,
@Param("minLon") double minLon,
@Param("maxLat")double maxLat,
@Param("maxLon") double maxLon,
@Param("distance") double distance);
}