게시글 검색 기능을 구현하기 전에 검색 기능을 수행할 수 있는 여러 방법들에 대해 성능을 비교하고 가장 좋은 방법을 선택해보자!
당근마켓 검색로직을 분석하다 알게된 사실(추측이니 너무 믿지는 말자!)
당근 마켓의 검색 시스템은 검색어를 띄어쓰기 단위로 분절하여 검색하는 듯하다. 예를 들면, "구찌" 를 검색하면 그에 대한 결과가 잘 나오지만 "구 찌"로 검색하면 "구"가 포함된 단어와 "찌"가 포함된 단어가 "모두"있는 결과만 나오게 된다. 이로써 검색어의 띄어쓰기 단위로 분절하고 분절된 단어들은 AND 연산으로 묶여 질의되는 것으로 추측하여 이에 맞게 구현했다!
성능 체크하기
성능 측정을 위한 비교 대상은 3가지로 삼았다. 일단 검색의 기본이라고 생각하는 Like "%query%" 문, MySQL Full Text Search, 그리고 ElasticSearch이다. 성능 측정 지표는 질의 수행 시간으로 삼았다.
1. MySQL 기본 검색 Like 문 사용한 경우(feat. QueryDsl) vs Full Text 쿼리
결론부터 말하자면 Full Text 쿼리가 기본 검색 Like문보다 속도가 빠르다.
따라서, 검색 대상이 되는 Title, Content 중 Content의 길이를 당근 마켓의 일반적인 글 길이라고 생각하는 300자 내외로 잡고 100000개 로우에 대해 다시 테스트 해보았다.
Like 문의 수행 시간은 0.035초, Full Text Search의 수행 시간은 그에 비해 3~4배정도 빨랐다.
2. MySQL 을 인덱싱 해볼까?
이 방법은 Like문이 찾고자 하는 검색어 앞 뒤로 '%' 가 붙어야하기 때문에 인덱스를 탈 수 없어 사용할 수 없는 방법이다.
3. ElasticSearch를 적용해볼까?
ElasticSearch는 역색인 구조로 인해 O(1)의 시간 안에 전문검색을 수행할 수 있는 반면 MySQL Full Text는 B-tree에 데이터를 저장하기 때문에 O(logN)의 시간복잡도를 가지므로 ES가 더 빠르다.
또한, ElasticSearch의 경우 형태소 분석 성능이 MySQL보다 더 뛰어나다. 즉, ElasticSearch는 한글 형태소 분석기로 Nori 토크나이저를 사용하면 형태소 분석된 결과들을 역색인하여 저장할 수 있고 이 특징 때문에 빠른 검색이 가능하다는 장점이 있다.
구현에 애를 먹긴했지만 결론부터 말하자면 Title과 Content를 동시에 질의하는 Criteria 방식의 동적 쿼리는 구현할 수 없었다. 따라서, NativeSearchQuery를 사용해서 동적쿼리를 작성했는데 검색 결과가 올바르게 나왔다.
데이터의 양이 늘어나면 역색인 구조의 장점으로 인해 ES가 더 좋게 나올 것임을 추측해볼 수 있고, 더불어 Nori 토크나이저를 사용하여 형태소 분석이 가능하기 때문에 더 좋은 성능의 검색 결과가 나옴을 알 수 있다!
따라서 이번 당근마켓 클론 코딩 프로젝트에서는 검색 기능으로 ElasticSearch를 사용해 구현했다!
번외로 Nori 토크나이저의 한글 형태소 분석 예시!
위와 같은 텍스트를 형태소 분석하면 아래와 같은 결과가 나와 저장된다!
{
"tokens": [
{
"token": "고장나",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "선풍",
"start_offset": 4,
"end_offset": 6,
"type": "word",
"position": 2
},
{
"token": "기",
"start_offset": 6,
"end_offset": 7,
"type": "word",
"position": 3
},
{
"token": "팔",
"start_offset": 8,
"end_offset": 9,
"type": "word",
"position": 4
}
]
}
꽤나 성능이 좋지 않은가?!!
'개인 공부' 카테고리의 다른 글
CS 공부 - HTTP (0) | 2023.03.24 |
---|---|
WebMvcTest에서 MockMVC로 실패 테스트하기 (0) | 2023.03.04 |
정적 팩토리 메서드 (0) | 2022.11.21 |
Logback.xml 동일 패키지 내 다른 레벨 처리 (2) | 2022.11.10 |
Garbage Collector 동작원리 (0) | 2022.11.01 |