grep

Engineering

Elasticsearch 거리 기반 가중치로 검색 랭킹 최적화하기

Whale여기어때

2025년 12월 8일

원문에서 보기 ↗

안녕하세요~ 여기어때 랭킹추천팀에서 랭킹 추천 개발을 하고 있는 웨일입니다!

여기어때 검색 서비스 중 좌표기반 검색은 Elasticsearch( 이하 ES )를 활용하여 다양한 방식의 검색 및 정렬을 제공하고 있습니다.

특히 나의 위치나 특정 위치에서 특정 반경 내 검색을 하는 반경검색이나, 특정 폴리곤 내 해당 제휴점이 있는지 검색하는 폴리곤 검색은 좌표점을 기반으로 하는 대표적인 검색 방식입니다.

이러한 서비스의 기능은 앱 내에 지도 검색 파트에 적용되어 있으며, 키워드 기반의 좌표점이나 지도 재검색 시 ES검색을 통하여 검색 결과를 전달하여 화면에 노출되게 됩니다.

앱 내 지도 검색 서비스

여기어때앱 지도검색 페이지에서 줌인, 줌아웃 후 재검색 할 경우 반경이 변경되면서 검색이 되고, 이동시 해당 좌표점을 기준으로 재검색을 수행하는 등 사용자의 행동에 따라 가변적인 검색 방식을 수행 하게 됩니다.

이렇게 일반적인 검색에서 유기적으로 검색을 수행하여 서비스 하는 반면 특정 좌표점을 기준으로 거리가 가까운 제휴점의 노출 순서가 중요한 경우에는 단순 필터 개념의 검색으로는 한계가 있습니다.

나이아가라 폭포 기준으로 가까우면서 좋은 제휴점이 좋지 않을까?

이에 기존 랭킹 점수에 거리별 가중치를 부여함으로써 랭킹이 높으면서 거리가 가까운 제휴점이 상위 랭크로 올라오게 하는 방법을 활용함으로써, 거리의 중요함과 랭킹의 중요함을 복합적으로 가지는 제휴점을 노출 시키는 방법을 공유하려고 합니다.

  1. 거리별 반경 가중치

특정 좌표점을 기준으로 제휴점을 검색할 때, geo_distance를 활용하여 거리별로 weight를 부여함으로써 기존 랭킹에 weight를 곱하여 거리별 랭킹을 차등 분배하는 방식입니다.

{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}  // 기존 쿼리
      },
      "functions": [
        {
          "filter": {
            "geo_distance": {
              "distance": "3km",
              "location": {
                "lat": 37.5665,
                "lon": 126.9780
              }
            }
          },
          "weight": 1.0
        },
        {
          "filter": {
            "geo_distance": {
              "distance": "5km",
              "location": {
                "lat": 37.5665,
                "lon": 126.9780
              }
            }
          },
          "weight": 0.5
        },
        {
          "filter": {
            "match_all": {} 
          },
          "weight": 0.1
        }
      ],
      "score_mode": "first",
      "boost_mode": "multiply"
    }
  }
}

특정 거리에서는 절대적인 가중치를 부여하는게 가능한 쿼리 입니다.

하지만, 기준점 ( 3Km 나 5Km ) 에서급격하게 가중치가 부여되는 단점이 있어 보완해야되는 부분이 생기는 쿼리 입니다.

  1. decay 함수 가중치

특정 거리에서는 절대적인 가중치를 부여하는 것이 가능한 쿼리 입니다.

하지만, 기준점 ( 3Km 나 5Km ) 에서급격하게 가중치가 부여되는 단점이 있어 보완해야 하는 부분이 생기는 쿼리 입니다.

점진적으로 감소 한다는말은 위의 구간별 거리 가중치와는 다르게 급격한 구간이 최대한 없어지며 유연한 값을 부여 할 수 있게 됩니다.

decay function graph

위의 이미지와 같이 decay function에서 제공하는 function은 총 3가지이며 아래와 같은 특성을 가집니다.

decay function 종류

거리 가중치를 부여 할 때 유연한 곡선값을 가지는 exp나 gauss를 가장 많이 활용하므로, 아래는 gauss 함수를 활용하여 간단한 ES 쿼리를 활용하여 검색이 가능합니다.

{
  "query": {
    "function_score": {
      "query": { "match_all": {} }, // 기본 검색 조건
      "functions": [
        {
          "gauss": { // 가우시안 함수 사용
            "location": {
              "origin": "37.5665, 126.9780", // 중심 좌표 (Origin)
              "scale": "5km", // 5km에서 점수가 50%로 감소
              "offset": "2km" // 중심에서 2km까지는 가중치 1.0 유지 (평탄 구간)
            }
          }
        }
      ],
      "boost_mode": "multiply" // 최종 점수 = 기본 점수 * 감쇠 가중치
    }
  }
}

origin 을 기준으로 scale과 offset을 적절하게 활용하면 기존 랭킹 점수와 연계하여 유연한 거리 가중치를 가져갈 수 있습니다!

다만, 거리가 너무 멀어진 경우, decay 값이 기계적으로 곱 연산 할 경우 0으로 수렴될 때 값이 0으로 바뀌어 기존 랭킹 점수도 무시되는 경우가 생기니 이점 유의해서 작업해야 합니다.

이번 글에서는 Elasticsearch의 좌표점 검색, geo_distance와 decay function을 활용하여 거리 기반 가중치를 랭킹 점수에 적용하는 방법을 살펴보았습니다.

구간별 거리 가중치 방식은 구현이 간단하고 명확한 기준을 제시할 수 있지만, 경계값에서 급격한 점수 변화가 발생할 수 있습니다.

반면 decay function을 활용한 방식은 거리에 따라 점진적으로 가중치가 감소하여 보다 자연스러운 검색 결과를 제공할 수 있습니다.

여러분의 서비스에서도 거리 기반 가중치를 활용하여 사용자에게 더 나은 검색 경험을 제공해보시기 바랍니다!

긴 글 읽어주셔서 감사합니다! 😊