legacy/Pin-Table 성능 개선 기록

검색 성능 개선 #12 Stop-word / ngram parser

3hoon 2023. 2. 26. 15:46

왜 Full-Scan보다 결과가 적게 나왔을까?

  • 이유는 Stop-word parser와 ngram parser 때문 
    • Stop-word parser 방식은 공백을 기준으로 인덱싱을 하는데, 한글의 특성을 생각 했을 때 적합한 방식은 Ngram 방식일 것 같아서 ngram방식으로 리인덱싱을 하였음
  • 2차 테스트 결과 비교:

Full-Scan

Full-Text Index(Stop-word) 검색

Full-Text Index(Ngram) 검색

⇒ 테스트 결과 : Stop-word parser > Full Scan > ngram parser


왜 Full-Scan보다 결과가 많이 나왔을까?

  • ngram parser를 적용하여 “순대국”뿐만 아니라 순대라는 단어까지 포함되었기 때문이다.
  • ngram은 최소 2글자로 잘라서 인덱싱을하고, 자연어 모드의 검색을 이용하였다.

🔎 Full-text Index의 검색 모드

  • Boolean Mode 검색을 이용한 검색 결과🔻

Full Scan

Full-Text index ngram BooleanMode

⇒ Boolean 모드로 검색할 경우 동일한 갯수의 데이터를 리턴하지만 속도는 향상된것을 볼 수 있다.


그럼 다 ngram parser를 적용하는것이 좋을까?

⇒ 아니다! 프로젝트에서 도로명 주소에 ngram parser를 적용하였을 때 오히려 검색 정확도가 감소했다.

⇒ 이유는 용산구를 검색할때 “용산”, “산구” 처럼 모두 검색이 되어서 유사한 다른 주소까지 나오면서 정확도가 감소하였다.

(ngram으로 인덱싱된 full-text index에서 용산구로 조회한 결과 창원시의 성산구까지 나오는것을 확인했다.)

 

⇒ 도로명은 stop-word parser의 적용이 필요!

 적용 후 검색 속도 및 정확도가 상승 하였다.


full text index 검색 모드

 

1. 자연어 검색(natural search)

  • 검색 문자열을 단어 단위로 분리한 후, 해당 단어 중 하나라도 포함되는 행을 찾는다.

ex) SELECT * FROM “테이블명" WHERE MATCH (“검색컬럼명") AGAINST (‘맛집' IN NATURAL LANGUAGE MODE);

 

2. 불린 모드 검색(boolean mode search)

  • 검색 문자열을 단어 단위로 분리한 후, 해당 단어가 포함되는 행을 찾는 규칙을 추가적으로 적용하여 해당 규칙에 매칭되는 행을 찾는다.
  • 검색의 정확도에 따라 결과가 정렬되지 않는다.
  • 구문 검색이 가능하다.
  • 필수(+), 예외(-), 부분(*), 구문(“ ") 연산자를 사용할 수 있다

ex) SELECT * FROM “테이블명" WHERE MATCH (“검색컬럼명") AGAINST (‘+대구*+닭*+맛집*' IN BOOLEAN MODE);

 

3. 쿼리 확장 검색(query extension search)

  • 2단계에 걸쳐서 검색을 수행한다. 첫 단계에서는 자연어 검색을 수행한 후, 첫 번째 검색의 결과에 매칭된 행을 기반으로 검색 문자열을 재구성하여 두 번째 검색을 수행한다.
  • 이는 1단계 검색에서 사용한 단어와 연관성이 있는 단어가 1단계 검색에 매칭된 결과에 나타난다는 가정을 전제로 한다.

full text index 인덱싱 기법 ( Built-in parser)

 

1. Stop-word parser

  • Stop-word 기법

Input : "나는 매일이 지옥 같았습니다.”

Stop-word : “ ”(공백) => 공백은 디폴트 값

Token : 나는 | 매일이 | 지옥 | 같았습니다.

공백을 기준으로 4개의 토큰이 인덱싱

 

2. N-gram parser

  • n-gram 기법을 사용하여 할당한 토큰의 크기 n만큼씩 데이터를 인덱스로 파싱해두었다가 사용하는 파서

Input : “나는 김치찌개가 좋습니다.”

N-gram : n=2

Token : 나는 | 는  |  김 | 김치 | 치찌 | 찌개 | 개가 | 개  |  좋 | 좋습 | 습니 | 니다 | 다. => 중에서 Token 2가 아닌 “는 “,” 김”, “개 “, “ 좋” 은 제거

나는 | 김치 | 치찌 | 찌개 | 개가 | 좋습 | 습니 | 니다 | 다. => 로 인덱싱