사전 결과 그룹핑
개념

결과 그룹핑

gabury1고친 사람 github-actions[bot]

결과 그룹핑은 검색 결과에서 한 무리에 드는 것들을 하나로 묶어 보여 줍니다. 쇼핑몰에서는 운동화 한 모델이 색상마다 따로 검색되어 첫 화면을 혼자 채우곤 합니다. 그룹핑은 모델마다 대표 한 켤레만 앞에 세우고 나머지 색상을 그 아래로 접습니다. 그만큼 첫 화면에 여러 모델이 올라옵니다.

쉽고 빠른 이해

결과 그룹핑은 같은 무리의 검색 결과를 묶어 대표만 앞에 세웁니다. 색상만 다른 운동화 네 켤레가 「에어 러너 흰색 · 같은 모델 3건 더」 한 줄로 줄어드는 식입니다.

이게 없으면 비슷한 결과가 첫 페이지를 독차지합니다. 사용자는 다른 모델이 있는지도 모른 채 페이지를 넘겨야 합니다.

어떻게 도나:

  1. 검색어로 결과를 얻어 점수 순으로 줄 세웁니다
  2. 결과마다 모델명처럼 묶는 기준이 되는 값을 읽어 같은 값끼리 한 그룹으로 모읍니다
  3. 그룹마다 점수가 가장 높은 결과를 대표로 세웁니다. 그룹끼리는 대표의 점수 순으로 섭니다

대가는 셈이 무거워진다는 것입니다. 그룹핑이 없으면 점수 상위 몇 건만 추려 두면 됩니다. 그룹핑은 결과마다 묶는 값을 읽어야 합니다. 접힌 건수까지 세려면 결과를 끝까지 훑어야 합니다.

페이지와 전체 건수도 결과 한 건이 아니라 그룹 하나를 단위로 다시 따져야 합니다.

상세

이 절은 운동화 여덟 켤레가 검색된 작은 쇼핑몰을 예로 듭니다. 그룹핑이 결과를 어떻게 묶고 무엇을 대표로 세우는지 따라간 뒤, 패싯이나 데이터베이스의 묶기와 무엇이 다른지, 무엇이 비싸지는지를 봅니다.

서점 진열대 비유

서점에서 소설 한 권을 찾는다고 합시다. 진열대에는 같은 소설의 양장본, 문고본, 개정판이 한 칸에 모여 꽂혀 있습니다.

손님은 칸 맨 앞의 한 권만 보고도 그 칸이 무슨 책인지 압니다. 다른 판이 궁금하면 그 칸 안을 들여다봅니다. 덕분에 진열대 한 줄에 여러 책이 나란히 섭니다.

한쪽으로 쏠리는 결과 목록

검색이 찾아 주는 대상 한 건을 문서라고 부릅니다. 쇼핑몰 검색이라면 상품 하나가 문서 하나입니다.

문서는 모델명, 색상 같은 칸을 갖습니다. 이 칸 하나를 필드라고 합니다. 그룹핑은 필드 하나의 값을 보고 문서를 묶습니다.

검색 엔진은 문서마다 검색어에 얼마나 잘 맞는지를 수로 매깁니다. 이 수가 점수입니다. 결과 목록은 점수가 높은 순으로 섭니다. 이렇게 순서를 매기는 일을 랭킹이라고 합니다.

「운동화」로 찾았더니 아래 여덟 켤레가 나왔다고 합시다. 이 절의 예는 전부 이 여덟 켤레로 합니다.

순위 모델명 색상 점수
1 에어 러너 흰색 9.1
2 에어 러너 검은색 8.8
3 에어 러너 회색 8.5
4 클라우드 워크 흰색 8.2
5 에어 러너 빨간색 7.9
6 트레일 X 검은색 7.5
7 클라우드 워크 회색 7.0
8 시티 런 흰색 6.4

색상마다 상품을 따로 등록하는 쇼핑몰이 많습니다. 그러면 에어 러너 한 모델이 문서 넷이 됩니다. 넷은 이름과 설명이 거의 같아서 점수도 비슷하게 받습니다.

한 페이지에 세 건을 보여 준다면 첫 페이지는 에어 러너 흰색, 검은색, 회색으로 끝납니다. 사용자는 다른 모델이 있는지도 모른 채 다음 페이지를 넘겨야 합니다. 비슷한 결과가 목록 윗부분을 채우는 이 문제를 풀려고 그룹핑을 씁니다.

같은 쏠림은 다른 검색에서도 납니다. 웹 검색에서는 한 사이트의 페이지들이 위를 채웁니다. 게시판 검색에서는 한 글타래의 댓글들이 몰립니다.

그룹 키와 대표 문서

무엇끼리 묶을지는 필드 하나로 정합니다. 이 필드를 그룹 키라고 부릅니다. 위 예에서는 모델명이 그룹 키입니다. 웹 검색이라면 사이트 주소가, 게시판이라면 글타래 번호가 그룹 키가 됩니다.

그룹 키 값이 같은 문서들이 그룹 하나를 이룹니다. 여덟 켤레를 모델명으로 묶으면 그룹이 넷 생깁니다.

그룹 든 문서 가장 높은 점수
에어 러너 흰색 · 검은색 · 회색 · 빨간색 9.1
클라우드 워크 흰색 · 회색 8.2
트레일 X 검은색 7.5
시티 런 흰색 6.4

그룹마다 맨 앞에 세울 문서 하나를 고릅니다. 이 문서를 대표 문서라고 합니다. 대개 그룹 안에서 점수가 가장 높은 문서가 대표가 됩니다.

그룹끼리의 순서는 대표 문서의 점수로 정합니다. 에어 러너의 대표는 9.1점이라 맨 앞에 섭니다. 클라우드 워크가 8.2점으로 뒤를 잇습니다.

그룹을 만드는 코드

묶는 코드는 몇 줄이면 됩니다. 점수 순으로 선 결과를 한 번 훑으며 그룹 키 값마다 목록에 넣습니다.

아래는 파이썬으로 여덟 켤레를 모델명으로 묶은 것입니다. hits 가 점수 순으로 선 결과 목록입니다. 튜플 하나가 문서 하나입니다.

groups 는 모델명마다 색상 목록을 담는 딕셔너리입니다. setdefault(model, []) 는 그 모델명이 아직 없으면 빈 목록을 만들어 넣은 뒤 돌려줍니다. 이미 있으면 있던 목록을 돌려줍니다. 줄 끝 주석이 그 줄이 내는 값입니다.

Python
hits = [  # 점수 높은 순
    ("에어 러너", "흰색", 9.1),
    ("에어 러너", "검은색", 8.8),
    ("에어 러너", "회색", 8.5),
    ("클라우드 워크", "흰색", 8.2),
    ("에어 러너", "빨간색", 7.9),
    ("트레일 X", "검은색", 7.5),
    ("클라우드 워크", "회색", 7.0),
    ("시티 런", "흰색", 6.4),
]

groups = {}
for model, color, score in hits:
    groups.setdefault(model, []).append(color)

names = list(groups)
names[0]                  # '에어 러너'
names[1]                  # '클라우드 워크'
len(names)                # 4
groups["에어 러너"][0]    # '흰색'
len(groups["에어 러너"])  # 4

결과가 점수 순으로 들어오므로 그룹마다 처음 들어간 문서가 그 그룹에서 점수가 가장 높은 문서입니다. 그래서 목록 첫 칸이 곧 대표 문서입니다.

그룹의 순서도 공짜로 얻습니다. 파이썬 딕셔너리는 넣은 순서를 지킵니다. 그룹이 처음 생긴 순서가 곧 대표 점수 순서라서 names 는 따로 정렬하지 않아도 에어 러너, 클라우드 워크, 트레일 X, 시티 런 순입니다.

묶은 결과를 보여 주는 두 방식

묶은 뒤 화면에 내는 방식은 크게 둘입니다. 그룹마다 문서를 몇 건씩 함께 보여 주는 방식이 하나입니다. 대표 한 건만 보여 주고 나머지를 접는 방식이 또 하나입니다.

앞의 방식을 그룹 보기라고 부르겠습니다. 그룹마다 머리글을 달고 그 아래 상위 몇 건을 늘어놓습니다. 게시판 검색에서 글타래마다 맞는 댓글 두세 개를 함께 보여 주는 화면이 이렇습니다.

뒤의 방식은 접기입니다. 결과 목록 모양은 보통 검색과 같습니다. 그룹마다 대표 한 줄만 남기고 「같은 모델 3건 더」 같은 링크를 붙입니다. 이 방식을 필드 접기(field collapsing)라고도 부릅니다.

방식 그룹마다 보이는 문서 화면 모양
그룹 보기 상위 몇 건 그룹 머리글 아래 짧은 목록
접기 대표 한 건 보통 결과 목록에 「N건 더」 링크

여덟 켤레를 접기로 보이면 한 페이지 세 건에 세 모델이 섭니다. 쏠림이 있던 첫 페이지와 견주면 차이가 큽니다. 네 번째 그룹인 시티 런은 다음 페이지로 갑니다. 아래 그림이 그 첫 페이지입니다. 점선 아래가 접혀서 안 보이는 문서입니다.

flowchart TD
    P["첫 페이지 · 그룹 세 개"]
    P --> A["에어 러너 흰색 · 9.1"]
    P --> C["클라우드 워크 흰색 · 8.2"]
    P --> T["트레일 X 검은색 · 7.5"]
    A -.-> A2["접힌 3건 · 검은색 · 회색 · 빨간색"]
    C -.-> C2["접힌 1건 · 회색"]

패싯과의 차이

패싯도 필드 값으로 결과를 가릅니다. 패싯은 값마다 몇 건인지 세어 결과 옆에 따로 보여 줍니다. 결과 목록 자체는 건드리지 않습니다.

그룹핑은 결과 목록을 바꿉니다. 건수 대신 문서를 보여 줍니다. 모델명 패싯이 「에어 러너 4 · 클라우드 워크 2」를 띄울 때 그룹핑은 에어 러너 흰색 한 켤레를 띄웁니다.

둘은 한 화면에 함께 쓰입니다. 옆에서는 패싯이 건수를 보여 줍니다. 가운데 목록은 그룹핑이 정리합니다.

데이터베이스 묶기와의 차이

SQL(Structured Query Language)의 GROUP BY 도 같은 값끼리 묶습니다. 묶은 뒤에는 그룹마다 한 줄만 남습니다. 그 줄에는 개수나 최댓값 같은 셈 결과만 담깁니다. 이렇게 여러 값을 하나로 접는 계산을 집계라고 합니다.

GROUP BY model 로는 모델마다 가장 높은 점수가 9.1이라는 것까지 얻습니다. 그 점수를 받은 문서가 흰색이라는 것은 못 얻습니다. 그룹핑이 원하는 것은 셈이 아니라 그룹마다 맨 앞의 문서 그 자체입니다.

SQL 로 같은 결과를 내려면 윈도 함수를 씁니다. 윈도 함수는 행을 접지 않습니다. 대신 그룹 안에서 행마다 순번이나 순위를 매겨 줍니다. 아래 쿼리는 hits 테이블에 앞의 여덟 켤레가 들어 있다고 보고 씁니다.

SQL
SELECT model, color, score
FROM (
  SELECT model, color, score,
         ROW_NUMBER() OVER (
           PARTITION BY model
           ORDER BY score DESC
         ) AS rn
  FROM hits
) ranked
WHERE rn = 1          -- 모델마다 한 줄
ORDER BY score DESC;  -- 4줄, 9.1 이 맨 위

PARTITION BY model 이 모델마다 그룹을 가릅니다. ROW_NUMBER() 는 그룹 안에서 점수 높은 순으로 1, 2, 3 하고 번호를 붙입니다. 바깥에서 1번만 남기면 그룹마다 대표 문서 한 줄이 남습니다.

rn = 1 을 rn <= 3 으로 바꾸면 그룹마다 세 건씩 남습니다. 앞에서 본 그룹 보기 방식이 됩니다.

페이지와 전체 건수

그룹핑을 켜면 페이지를 세는 단위가 문서에서 그룹으로 바뀝니다. 한 페이지에 세 건이라는 말이 그룹 세 개라는 뜻이 됩니다. 두 번째 페이지는 네 번째 그룹부터 시작합니다. 결과를 페이지로 나눠 보여 주는 일 전반은 페이지네이션이 다룹니다.

전체 건수도 둘로 갈립니다. 검색어에 맞는 문서는 여덟 건입니다. 그룹은 네 개입니다. 화면에 「검색 결과 8건」이라고 적을지 「4개 모델」이라고 적을지 정해야 합니다.

그룹 수를 세는 일은 문서 수를 세는 일보다 무겁습니다. 서로 다른 그룹 키 값이 몇 개인지 알려면 결과를 끝까지 훑어 값을 모아 봐야 합니다. 그래서 그룹 수는 빼거나 대략으로만 보여 주는 화면도 있습니다.

셈이 무거워지는 까닭

그룹핑이 없으면 검색 엔진은 점수 상위 몇 건만 추려 들고 있으면 됩니다. 한 페이지 세 건이라면 지금까지 본 문서 가운데 점수가 높은 세 건만 남기고 나머지는 버립니다. 문서마다 모델명 같은 필드를 읽을 필요도 없습니다.

그룹핑은 그렇게 줄일 수 없습니다. 결과 문서마다 그룹 키 값을 읽어 어느 그룹에 드는지 가려야 합니다. 그룹마다 건수나 상위 몇 건까지 내려면 결과를 끝까지 훑으며 그룹마다 따로 적어 둬야 합니다.

검색 엔진은 문서마다 번호를 붙여 관리합니다. 이 번호를 문서 번호라고 부릅니다. 그룹 키 값을 빨리 읽으려면 문서 번호만으로 그 문서의 필드 값을 바로 꺼낼 수 있어야 합니다.

그래서 검색 엔진은 그룹 키로 쓰는 필드의 값만 따로 모아 문서 번호 순서로 늘어놓아 두곤 합니다. 번호를 알면 몇 번째 값을 읽을지 바로 알아서 문서를 통째로 열지 않아도 됩니다. 필드 하나의 값만 한곳에 이어 담는 이 방식을 열 지향 저장이라고 합니다.

검색 엔진이 문서를 빨리 찾으려고 미리 만들어 둔 찾아보기를 색인이라고 합니다. 문서가 많아지면 색인도 한 서버에 담기 어려울 만큼 커집니다.

그러면 색인을 여러 서버에 나눠 담습니다. 나눈 조각 하나를 샤드라고 부릅니다. 검색어가 오면 샤드마다 따로 찾고 묶은 뒤 그 답을 한데 모읍니다.

에어 러너 네 켤레가 두 샤드에 두 켤레씩 흩어졌다고 합시다. 두 샤드가 저마다 「에어 러너 2건」이라고 답하므로 둘을 더해야 4건이 됩니다. 대표 문서도 샤드마다 하나씩 올라오니 둘 가운데 점수가 높은 쪽을 다시 골라야 합니다.

샤드가 자기 쪽 상위 그룹 몇 개만 보내 왔다면 어떤 그룹의 건수는 일부 샤드 몫이 빠져 있습니다. 그 건수와 상위 문서를 채우려면 샤드에 한 번 더 물어야 할 수 있습니다. 그래서 그룹 키가 같은 문서를 한 샤드에 모아 저장하는 방법을 쓰기도 합니다. 그러면 한 그룹이 한 샤드 안에서 끝나 합칠 것이 없습니다.

결과 군집화와의 차이

그룹핑과 이름이 비슷한 기능으로 결과 군집화가 있습니다. 결과 군집화는 문서 군집화를 검색 결과에 쓴 것입니다. 군집화는 문서 내용이 얼마나 비슷한지를 재서 무리를 스스로 만듭니다. 미리 정한 그룹 키가 없습니다.

그룹핑은 그룹 키 값이 같은지만 봅니다. 무리가 어떻게 나뉠지 미리 압니다. 군집화처럼 문서끼리 비슷한 정도를 잴 필요가 없어 셈이 그보다 단순합니다. 대신 묶을 필드가 없는 문서에는 쓸 수 없습니다.

쓸 때와 안 쓸 때

맞는 쓰임과 안 맞는 쓰임을 함께 놓아 봅니다.

하려는 일 그룹핑이 맞나
색상·크기만 다른 상품이 따로 검색되는 쇼핑몰 맞다. 모델마다 하나씩 세운다
한 사이트나 한 글타래가 결과를 채우는 검색 맞다
문서마다 그룹 키 값이 다 다른 경우 필요 없다. 그룹마다 한 건이라 목록이 안 바뀐다
한 무리 안의 차이를 견주어 보려는 검색 안 맞다. 접힌 문서를 하나씩 펼쳐야 한다
묶을 필드 없이 본문 글만 있는 검색 안 맞다. 결과 군집화가 맞는 쓰임이다

관련 항목

결과 그룹핑이 속하는 상위 분류

검색 · 검색 엔진 · 전문 검색 · 탐색적 검색

결과 그룹핑과 함께 검색 결과 화면을 이루는 기능

패싯 · 자동 완성 · 하이라이팅 · 랭킹 · 정렬 · 페이지네이션

같은 값끼리 묶는 데이터베이스 계산

GROUP BY · 집계 · 윈도 함수 · ROW_NUMBER · SQL

그룹 키를 읽고 그룹을 합치는 저장 구조

색인 · 역색인 · 열 지향 저장 · 샤드 · 샤딩

결과 목록의 쏠림을 다루는 다른 수단

문서 군집화 · 중복 제거 · 근사 중복 탐지 · 결과 다양화

결과 그룹핑을 제공하는 검색 라이브러리와 서버

Apache Lucene · Elasticsearch · OpenSearch · Solr

다른 이름: result grouping · field collapsing · 필드 접기 · 결과 접기 · 검색 결과 그룹핑 · 결과 묶기