본문 바로가기

프로젝트/여행지 오픈 API

[Elasticsearch] 회고 및 리뷰

목차

    성과

    Spring 서버 연동 및 API 생성 및 인프라 구축

    - spring data elasticsearch와 native search query를 사용한 API 서버 구축.

    - elasticsearch, kibana, logstash를 사용할 수 있는 서버 환경 구축. ES 버전은 7.11.2를 사용하였다.

    유사도 비즈니스 로직 구현

    1. 입력 검색어에 대한 오탈자 보정 후 유사 검색 결과 반환 및 비즈니스 로직 제공

    API 요청 당시 가장 큰 요구사항은 '오탈자'에 대한 올바른 검색 결과를 제공하는 것이었다.

    따라서 숙소, 관광지, 음식점의 데이터셋을 분석기와 커스텀 필터를 통해 인덱스에 저장하였다.

    이후 ngram과 fuzzy 방식을 융합하여 사용자의 요청에 따라 가장 유사한 검색 결과를 반환할 수 있도록 하였다.

    2. 전체 필드에 대한 전문 검색을 통한 입력 String에 대한 가장 큰 유사 검색 결과 및 비즈니스 로직 제공

    또한 사용자로부터 가중치 값을 입력받아 필드별 부스팅을 적용했다.

    이를 통해 문장을 입력받을 경우, 모든 틸드를 조회 후 가장 관련성이 높은 내용을 가져올 수 있다.

     

    3. 데이터 수집 및 신뢰성 판단 프로세스 적용

    더욱 많은 데이터와, 수집된 데이터의 신뢰성을 판단하여 정확하고 많은 데이터들을 수집하기 위한 로직을 고민했다.

    - 검색어 공백, 특수문자 고려, 스플릿하여 검색 풀 증가

    - null값 제거 및 처리

    - 수집 데이터 용어화 이후 신뢰성 비교 

    다음과 과정을 거쳤다. 자세한 내용은 아래 포스팅에 기술한다.

    https://csg1353.tistory.com/78

     

    [정리]analyzer를 사용한 수집 정보의 유사성 계산

    요약 0. 수집 데이터는 기존 데이터와 완벽 매칭되는 것이 아닌 부분 데이터 검색 결과값이다. 1. 기존 서비스는 null값 비율 50% 이상 : 노쓸모 2. 1차 개선 : null 배제 3. 2차 개선 : 유의미 데이터 중

    csg1353.tistory.com

     

     

    logstash 사용자 데이터 수집과 kibana를 통한 데이터 시각화

    1. 사용자 데이터 수집

    - SpringBoot 서버에서 API 요청이 들어왔을 경우 AOP와 logback을 통해 로그 데이터를 파일의 형태로 저장하게 하였다.

    - 이 logback 파일은 스프링 컨테이너 내부에 존재하지만, 볼륨 마운팅을 통해 EC2 외부의 폴더에서도 접근할 수 있다.

    - logstash 작성 파일을 통해 해당 로그 폴더에 접근 후 외부에 존재하는 Elasticsearch DB에 로그를 저장하게 하였다.

    - 이를 통해 자주 사용하는 아이피, 메서드(API), 시간대 등을 추적할 수 있다.

     

    구현 과정은 다음과 같다.

    https://csg1353.tistory.com/94

     

    [Logstash] 로그스태시로 로그 뽑아서 저장하기

    경로 맞추기 내 스프링부트 컨테이너 내부 경로와 외부 마운팅할 파일 경로를 맞춰줘야 한다. sudo docker exec -it elastic-container /bin/bash 를 통해 접속한 결과 이런 식으로 기본 루트 디렉토리가 /app임

    csg1353.tistory.com

    https://csg1353.tistory.com/90

     

    [LogBack]API 요청 로그 수집하기

    개요 API 요청에 따라 springboot에서 로그를 수집하고, 발생하는 로그를 ES의 인덱스에 추가하려고 한다. 전체적인 로직은 다음 포스팅들을 참고하였다. https://prohannah.tistory.com/182 Spring Logging (1) : HTT

    csg1353.tistory.com

     

    2. Kibana 데이터 시각화

    수집된 데이터를 인덱스에 도큐먼트 형태로 저장하고, 이를 kibana Dashboard를 통해 여러 차트의 형태로 나타내었다.

     

    https://csg1353.tistory.com/88

     

    [Kibana] Kibana 데이터시각화 구현

    https://www.elastic.co/guide/en/kibana/7.11/index-patterns.html Create an index pattern | Kibana Guide [7.11] | Elastic If you don’t set a default time field, you will not be able to use global time filters on your dashboards. This is useful if you have

    csg1353.tistory.com

     

    고민과 어려움

    데이터 수집 범위의 고민

    기존 공공데이터 API 데이터셋 기반으로 전자사전을 검색할 경우, 명칭이 달라 일치하는 데이터가 별로 나오지 않았다.

    이는 정확한 명칭을 통해 검색해야 하는데, 똑같은 말이지만 부분적으로는 명칭이 달랐기 때문이다.

     

    예를 들어 이런 식으로 '설악산 국립공원' 에 대한 정보지만, 데이터 API에는 다른 명칭으로 저장된 경우도 많았다.

    혹은 공백이 붙여있거나, 띄워져있기도 했다.

     

    해결 과정

    이를 위해 데이터 수집 단계에서 공백과 어절, 특수문자를 기준으로 스플릿하여, 부분 검색을 통해 연관 데이터들을 전부 수집하였다.

    이로 인해 기존 1만 5천여개의 전자사전 결과 데이터셋을 80만개(4GB)의 결과물로 확보할 수 있었다.

     

    데이터의 신뢰성과 후처리 고민

    데이터를 수집한 이후, 쓸모 없는 데이터를 정제하기 위한 로직이 필요했다.

    이를 신뢰성 로직을 사용하여 용어 간의 유사도를 분석하여 신뢰성 있는 데이터의 지표를 제시하였다.

     

    Null 배제 : 데이터의 명칭과 좌표를 활용하여 중복된 데이터를 제거하는 로직을 실행하였다.

    신뢰성 처리 : 수집된 데이터의 경우 연관이 없거나, 동음이의어의 이슈가 발생( ex : 유성은 지명이지만, 천문 용어인 유성 역시도 검색되었다)했다.

     

    신뢰성 로직의 경우, 글이 길어 해당 부분에 별도의 정리를 하였다.

    https://csg1353.tistory.com/78

     

    [정리]analyzer를 사용한 수집 정보의 유사성 계산

    요약 0. 수집 데이터는 기존 데이터와 완벽 매칭되는 것이 아닌 부분 데이터 검색 결과값이다. 1. 기존 서비스는 null값 비율 50% 이상 : 노쓸모 2. 1차 개선 : null 배제 3. 2차 개선 : 유의미 데이터 중

    csg1353.tistory.com

     

     

    키워드 추출 

    nori의 경우 한 글자도 토크나이징된다. 토큰화된 용어의 경우 유의미한 키워드로 사용할 수 있는 지표가 있었지만, ‘곳’, ‘등’ 등 의미 없는 한 글자의 단어들이 많았다.

     

    총체적 난국.. 한 글자가 토큰화 된다.

     

     

    이 문제를 해결하기 위해 초기 인덱스 설정 시 문장 유사도를 검색하는 기본 nori 분석기와 글자 수 제한 토크나이저 사용 및 특정 단어를 제외한 분석기를 별도로 분리하였다.

     

    또한 초기엔 이를 국립국어원 API를 사용하여 명사 비교 대조하려고 했으나, API 요청 대기 시간과 회수의 문제, 결정적으로 해당 글자 역시 명사라 명확한 구분이 불가능했던 점의 한계가 존재했다. 이 부분이 정확했다면 더욱 신뢰성 있는 결과를 낼 수 있었을 것이다.

     

    이에 대한 대안으로 집계 과정에서 별도 분석기를 사용하여 집계 순 단어 중 가장 유의미한 키워드를 내림차순으로 가져왔고, 결과를 모니터링하여 Stop words 필터에 비신뢰성 데이터를 추가하여 배제하였다.

     

    오탈자 검색 고민

    https://csg1353.tistory.com/81

     

    [ElasticSearch] 최종 인덱스, 중복 문제와 오탈자 검색의 고민

    인덱스 최종 수정 기존에는 필터 유무로 인덱스를 나눴는데. 이는 매우 비효율적인 짓이었다. 그냥 커스텀 분석기를 하나 추가하고, 하나의 인덱스에 적용하면 된다. 특히 match_term 등의 토큰화

    csg1353.tistory.com

     

    기존 nori 분석기를 활용하여 용어화 이후 유사도를 활용하는 방법은 분명 유의미한 효과가 있지만 정확한 오타를 보정하는 데 힘들었다.

    이는 분석기가 단어 단위의 용어로 자르기 때문인데, 자체적으로 이를 match를 통해 비교하는 건 부정확한 결과를 낼 확률이 높았다.

    따라서 더욱 유사한 검색 결과를 제공하기 위해 fuzzy 검색과 ngram 검색, 그리고 이를 모두 사용하는 해결 방법을 사용했다.

     

    최소 검색 결과 개수 보정

    • 이 과정에서 조회 파라미터를 최소 40개 정도로 잡아 유의미한 중첩 순서를 잡도록 하였다.
      개수가 적을 경우 조회 데이터셋 풀이 작아 부정확한 데이터들이 나올 확률이 높았다.
      예를 들어 특정 제목으로 5개를 검색했을 경우, Ngram / Fuzzy의 결과가 전부 겹칠 확률이 적어 둘 사이의 교집합을 찾기가 힘들었다.
      유사도 구분 로직의 핵심은 두 쿼리의 결과 중 겹치는 부분을 스코어를 합산하여 판정하는 것인데, 이 부분의 교집합을 최대한 늘려야 했다.

    가중치 : (Fuzzy, Ngram) 중 무엇을 우선시 할 것인가?

    • 가중치 판단 여부는 사용자가 직접 입력 파라미터를 설정하게 하였다.
      'FuzzyPrimary' bool parameter를 통해, 어떤 검색 결과를 우선시 할지 판단하게 하였다.
      해당 bool의 입력에 따라 7 : 3 비중으로 Fuzzy와 Ngram 중 스코어 결과가 가중된다.
      이렇게 적용한 이유는 오타를 보정하는 타입이 다르다고 판단했기 때문이다.
      - Ngram의 경우는 특정 오타보다는 전체적인 오타가 났을 시 부분적으로 동일한 결과를 뽑아오는 것에 유리하다.
      예를 들면, '한국미국타이어'를 '태국의미국타이어' 등으로 위치나 특정 단어를 잘못 쳤을 경우 유사도가 정확했다.

      - Fuzzy의 경우는 일반적으로 우리가 생각하는 오타를 보정하는 데에 유리하다.
      예를 들면, '대한민국'을 '데한민국' 이나, '대만민국' 이렇게 오타를 쳤을 경우 거리순에 따라 보정하기 좋았다.

      이 둘을 중첩해서 사용하며, 어느 부분에 더 가중을 줄 지 선택하게 하였다. 

     

    효율적 로직 개편 : bool 쿼리에 should 옵션을 사용하여 다수 요청을 한번에 보냄으로써 네트워크 부하 감소

    반복문을 통해 특정 검색어를 여러 번 요청하는 것보다, bool 쿼리문에 여러 검색어를 담아 한번에 보내고, 이를 List로 가져온 다음 서버 측에서 정렬하여 결과를 처리하는 로직을 사용하였다.

    이에 대한 결과로 기존 반복 요청 로직 대비 네트워크 오버헤드를 줄일 수 있었고, 평균 5배, 최대 10배의 시간 효율을 달성할 수 있었다.

    자세한 내용은 아래 게시글에 작성하였다.

     

    https://csg1353.tistory.com/86

     

    [Elasticsearch] 네트워크 오버헤드 효율 비교 및 개선(쿼리 변경)

    개요 기존 프로젝트에서 우리는 오타를 보정하기 위해 검색어와 가장 유사한 검색어들을 차등적으로 리스트의 형태로 제공했다. 이 과정에서 Ngram과 Fuzzy의 분석 결과를 요청하고, 이를 다시 합

    csg1353.tistory.com

     

     

    기타 : 보안과 인프라

    ElasticSearch 본체와 Kibana의 인프라 구성을 하였다.

    1. kibana 콘솔의 auto-boot. : 컨테이너화를 시키지 않았기에 시스템 단에서 system  파일을 통해 자동 부팅되게 설정하였다.

     

    2. x-pack 보안 설정 : elasticsearch에 계정과 SSL 인증서, xpack 설정을 추가하였다. 해킹을 통해 인덱스 초기화를 경험하였다.. 구축 과정에서 미리 설정했어야 하는데 아쉬움이 남는다.

     

    3. 리버스 프록시 : 2의 과정에서 구매한 도메인으로 접속 시 리버스 프록시 과정을 통해 kibana와 elasticsearch의 인프라 환경을 최종적으로 구축하였다.

    이 과정에서 kibana의 경우 header에 base64로 인코딩된 게스트용 계정값을 입력하여, iframe export시 우리 서버의 dashboard를 적용할 수 있게 하였다.

     

    4. logstash - elasticsearch 데이터 수집 파이프라인

    본 서버의 컨테이너에서 로그를 수집해야 하기 위해, 본체의 로그스태시 conf 파일 작성을 통해 외부 서버(서브 서버) 인프라와의 통신 라인을 구축하였다.

     

     

    아쉬운 점

    적용하지 못했던 아쉬운 부분 :

    1. papago api를 사용한 영문 변환 이후 영어 토큰 신뢰성을 적용하지 못한 것.

    만약 기존의 유사도 판단 로직에 덧붙여 이 텍스트를 '영문 변환' 이후 영어 텍스트를 비교했다면 이중 비교를 통해 더욱 정확한 값을 제공할 수 있었을 것이다.

    이 부분을 시간 상의 이후로 적용하지 못했던 점이 아쉽다.

     

    2. 오타 사전을 추가하지 못한 점 :

    API 요청에 따라 오타가 자주 발생하는 단어에 대한 사전을 만들어 이를 기반으로 검색어를 교정하는 방법을 적용할 수도 있을 것이라는 아쉬움이 들었다.

    사용자의 입력이 이 사전에 있는 단어와 유사할 경우, 사전에 정의된 올바른 단어로 교체할 수 있는 알고리즘을 너무 늦게 아이디어로 생각해, 이를 적용하지 못했다.

     

    적어놓은 아쉬웠던 부분은 추후 리팩토링을 통해 기능을 추가해보려고 한다.