800 words in content
8 minutes for read
약봉투 OCR 후처리 알고리즘을 통한 조회 최적화

인식한 상황#

OCR로 인식된 약봉투 이미지의 텍스트를 기반으로 의약품 정보를 조회하는 과정에서 성능 저하 문제가 나타났다.

  • 과도한 SELECT Query 발생: 평균 152회의 단어 검색이 일어나는 상황을 확인했다.

  • 거친 필터링 부족: 의약품과 무관한 단어들도 DB 검색 과정을 거치며 불필요한 부하를 초래했다.

  • 처리 속도 지연: OCR을 제외한 로직 실행 시간이 평균 1072ms 정도 소요되어, 사용자 경험을 저해하는 원인이 되었다. (OCR도 2~8초 걸리는데…ㅠ)

해결 과정#

이번에는 1학기에 배운 정규식을 생각해 보았다. 의약품 데이터(식약처 전문의약품 데이터)를 분석한 결과, 의약품명 특징 중 마지막 두 글자가 중복된 경우가 많다는 점을 발견했다. 사실상 정규식을 만들 수는 없겠지만, 강의 덕분에 유사점을 쉽게 찾았다. (손OO 교수님 감사합니다… 덕분입니다…)

2차 필터링 적용#

기존에는 Inference Score를 기반으로만 필터링하고 바로 DB에서 검색했다. 앞에서 찾은 마지막 두 글자만 있는 특성 목록을 구성하고, 이를 토대로 OCR 결과에서 불필요한 단어들을 2차적으로 필터링했다. 이 과정으로 평균 152회의 검색을 불필요한 단어를 삭제함으로써 20~30회로 크게 줄일 수 있었다.

Query 성능 최적화#

Explain Query을 활용하여 쿼리 실행 계획을 확인한 결과, Like 연산에 의한 Full Scan이 발생하고 있었다.

천천히 읽어보니 LIKE '%keyword%' 형태의 Left Like(문자열 앞부분에 와일드카드가 있는) 검색은 인덱스를 활용하기 어려워, Range Query 불가능에 따른 Full Table Scan이 발생하고 있었다… 공식 문서를 확인해보니 시작값을 기반으로 b+ tree를 구성하고 있어서 일어난다고 한다.

찾아보니 Full Text Search를 지원하는 것을 확인하고 Index를 도입하였다. dose 테이블의 name 컬럼에 Full Text Index를 적용하고, Natural Language Mode로 검색을 수행했다. 이를 통해 Like 기반의 Full Scan 대신, Full Text Search를 활용한 효율적인 인덱스 검색이 가능해졌다.

결과#

성능 개선 조치 이후, OCR을 제외한 의약품 정보 조회 로직 처리 시간이 크게 단축되었다. 개선 전에는 평균 1072ms 정도 걸렸지만, 개선 후에는 평균 120ms 정도 걸렸다. 이로써 사용자 만족도를 높일 수 있는 응답 시간을 확보했고, 시스템 부하를 줄여 더욱 안정적인 서비스 제공이 가능해졌다.

찾아보니 Elastic Search 같은 검색 엔진을 도입하면 더 좋아진다는데, 게시글 서비스가 생기면 이걸 사용해보는건 어떨지 생각하게 되었다.