$text, $search vs $regex In MongoDB

QQQ
nodejs backend
Published in
5 min readMar 24, 2021

검색 엔진 없이 MongoDB query만으로 최대한 검색해보기

$regex vs $text, $search

검색 엔진없이 필요한 정보를 DB query만으로 최대한 검색해보는 글입니다.

두 가지 비교 대상은 “1. 정규표현식 regexp 검색”“2. $text index 검색”입니다.

검색 엔진을 이용하는 것이 더 디테일한 값을 찾을 수 있지만, 검색엔진을 만들기가 부담스럽거나 필요성이 크지 않다면, 혹은 규모가 작은 서비스에서는 regexp$text & $search만으로도 괜찮은 검색 결과를 얻을 수 있습니다.

다만 한계가 있다면,

DB 검색의 한계

DB로만 검색을 한다면 띄어쓰기가 들어가 있는 데이터 (ex,”검정 치마”)를 띄어쓰기가 없는 키워드(ex. “검정치마”)로 검색한다면 찾을 수가 없습니다.
(검색 엔진을 만든다면 글자를 쪼개서 검색할 수 있겠지만 검색엔진 없이 DB만으로는 검색이 불가합니다.)

이 한계를 최대한 피하거나 우회하는 방법을 알아보도록 하죠.

1. 정규표현식(regex) Query

아래 User 모델로 진행하겠습니다.

위 Schema를 보면 text index는 설정되어있지 않습니다. 그러므로 아직 $text, $search는 이용할 수 없습니다. 그 대신에 “regex 정규 표현식”으로 검색이 가능합니다.

세명의 유저가 예제처럼 있습니다.

위 유저를 정규표현식으로 검색한다면,

정규표현식으로 가능한 Query

정규표현식 검색의 좋은 점은 단어가 100% 일치하지 않고 부분적으로 일치하더라도 검색이 됩니다. 아래처럼 “정치", “치마" 이렇게 검색하여도 “검정치마" 데이터가 잘 나오게 됩니다. 반면 아래 문단 다룰 index 검색으로는 단어의 부분을 검색하면 검색이 되지 않습니다.

그리고 여러개의 키워드를 넣더라도 키워드 중 하나라도 정규표현식에 맞으면 검색 결과에 포함되도록 할 수 있습니다.

보통 검색의 키워드로 하나의 문자열이 들어올텐데, 그 문자열이 한 단어로 구성되어있지 않을 때도 많습니다. (‘김치’ 처럼 한 단어로 검색할 때도 있지만 ‘배추 김치’처럼 두 단어가 합쳐진 상태로 검색할 수도 있죠.) 그럴 때는 직접 띄어쓰기를 기준으로 문자열을 나누어 하나하나 $regex query를 진행하면 됩니다.

“검정 파랑 빨강”으로 검색을 한다면, “검정”, “파랑”, “빨강” 중 하나라도 포함하는 문자열이 있다면 검색 결과에 포함됩니다.

Regex로 불가한 Query

만약 “파란 바지”(띄어쓰기 O)로 저장되어있는 데이터를 “파란바지”(띄어쓰기 X)로 검색한다면 검색이 되지 않습니다.

정규표현식 Query의 한계

#검색 관련성이 높은 순으로 결과를 보여줄 수 없다.

인풋으로 들어오는 문자열을 띄어쓰기 기준으로 split하여 단어 하나라도 매칭되는게 있다면 결과값으로 보여주기 때문에,(“단지 매칭되는가 안되는가” 만을 확인할뿐입니다.) 관련도에 따라서 검색 결과를 정렬할 수는 없습니다.

#데이터가 많아질수록 느려집니다.

정규표현식 Query 또한 검색엔진을 이용하는 것이 아니므로 검색하는 데이터가 많아지면 많아질수록 검색 성능이 저하됩니다.

2. Text Index Query ($test, $search)

위 UserSchema를 보면 name 필드에 index를 설정했습니다. 이제는 $text 검색이 가능합니다.

Model Schema에 text index가 설정되어있는 필드라면 + $text$index를 이용하여 Query한다면 알아서 띄어쓰기에 따라 나뉘어 한 단어 한 단어 키워드로 검색이 진행됩니다. (위 단락에서 정규표현식에서는 직접 split하여 검색을 해야했습니다.)

위 query문을 보면 키워드로 넣은 “검정 치마” 문자열이 ‘검정’, ‘치마’ 두 개로 나뉘어 검색하게 됩니다. 그리고 여기서 더 중요한 점은 검색 결과의 관련성을 계산하여 score값으로 전달해줍니다.score옵션을 sort하여 관련성이 높은 순서로 결과로 보여줄 수 있습니다.

여기서 더 중요한 점은 검색 결과의 관련성을 계산하여 score값으로 전달해줍니다.

Text Index 검색의 한계

Text Index 검색은 띄어쓰기 기준으로 나뉜 키워드가 정확히 100% 매칭되는 것만 검색 결과에 포함됩니다.

어떠한 필드가 동해물과 백두산이 마르고로 저장되어 있다면

동해물과, 백두산이, 마르고, 동해물과 마르고, 백두산이 마르고 등 정확히 키워드 하나하나에 맞게 매칭되는 것들만 결과 값에 포함됩니다.

그러므로 동해물과백두산이(띄어쓰기 X)로 검색한다면 어떠한 값도 반환되지 않습니다.

그리고 regex 처럼 부분적인 검색도 불가합니다. 동해물, 백두산으로 검색하면 하나도 매칭되지 않습니다. (동화물과동해물 은 다르고, 백두산이백두산은 100% 매칭되지 않기때문에)

“정규표현식 검색”과 “Text Index 검색“모두 불가한 것이 있습니다.

띄어쓰기된 상태로 저장되어 있는 데이터를 띄어쓰기 안 한 상태로 검색할 때가 그렇습니다.
“검정 치마”(띄어쓰기 O)로 저장되어 있는 데이터를 검색할 때 “검정치마”(띄어쓰기 X)로 검색하면 검색 결과에 포함되지 않습니다.

이러한 한계가 있긴하지만 규모가 크지 않은 서비스라면 이 정도의 한계는 크게 불편하지 않을 수 있습니다. 개인적으로 여러 어플들에서 검색 엔진을 따로 구현해두지 않아도 서비스가 잘 진행되는 것을 많이 봤습니다.

어떤 형태로 입력해도 연관된 데이터를 얻고 싶다면 검색 엔진을 찾아보시기 바랍니다. 대표적으로 “엘라스틱 서치”가 있습니다.

--

--