[엘라스틱서치] graph API에 대해서 - forewalk/elastic GitHub Wiki

Elasticsearch

graph


이번 프로젝트를 진행하면서 _graph API를 여러 테스트를 하면서 재미있는 기능이라고 생각이 들었다. _graph는 기본적으로 vertices[정점]과 connection[연결정보: 홉] 그리고 control과 마지막으로 query로 이뤄져 있다. 이 네가지를 이용하여 말그대로 탐험하는 기능이다. 왜 그래프 API가 explore인지 그래, 테드의 말대로 철학을 이해하고자 하면 좀더 본질적으로 이 녀석이 뭐하고자 하는건지 이해할 수 있었다.

일단 기본적으로 그래프의 기능은 많은 단어 풀에서의 연관성을 찾는 것이다. 이때의 단어풀이라 함은 개별적 연결성이 없는 단어풀이 아닌, array 형태의 단어 풀이어야 한다. 즉, A단어는 B단어와 같은 다큐먼트에 존재한다는 것이 기본 전제조건인데, 테드한테 물어봤더니 BM25알고리즘을 사용하는건 아니라 한다.(엘라스틱에서도 잘 모르는듯... case에 올려도 무슨 알고리즘인지 얘길 안해준다.) "Vertex에 대해 weight 계산이 일어나지만 BM25와는 다른식으로 계산되는 점" 이라는 애매한 말을 남기고 case는 닫혔다.

그냥 느낌엔... TF/IDF + significant terms인 듯하다. >> 이것도 아니라는뎅?? 이게 무슨말이냐면, 일단 기본적으로는 자주 같이 등장하는 단어는 분명 추출한다. 왜냐면 min_doc_count 옵션이 있지 않은가? 적어도 X이상의 문서에 함께 나와야 한다.가 필수조건이다. 거기에 significant를 어떻게 뽑냐를 자세히 보면, 낮은 빈도수임에도 불구하고, 어느 특별한 단어가 무조껀 나오는 형태. << 단순 갯수의 문제가 아닌 %로 특별하게 규정할 수 있는 terms. 그것이 significant 기준인 듯하다.

수석 고객, 이하 박사님 ㅎ 박사님의 요구사항 중 뭐가 있었냐면, 예전 통계 교양수업시간에 나도 들은 얘기인데, 기저귀와 맥주와 같은 연관관계 terms를 뽑고 싶다는 요구사항이었다. 뭐 통계 수업에 들은 내용으로는 월마트였나? 그 마트에서 영수증 데이터를 분석하던 중, 기저귀와 맥주가 함께 팔리는 사례가 너무 많아 확인해보니 아빠들이 엄마 심부름으로 기저귀 사오래서 기저귀를 사다가 맥주 하나 같이 사다더라... 뭐 이런건데, 실재로 이 마트에선 맥주와 기저귀를 바로 가까이에 배치함으로써 맥주의 판매량이 월등하게 높아졌다는 재미있는 통계자료가 있다. 이런 얘기다. 직접적인 관계, 우리 박사님 언어를 빌리자면 같은 도메인에 있는 단어들을 연관어로 뽑고 싶은게 아닌 크로스도메인에 위치한 단어들이 많이 뽑혔으면 좋겠다. 이거였는데, 그래프가 그런 특별한 단어를 뽑기에 좋은 API란건 알겠지만, 이걸 어떻게 설계해야 특별한 단어를 많이 뽑을 수 있을까는 내 계속된 숙제였다.

한편, 그래프는 모든 데이터를 분석하기엔 시간이 너무 오래 걸리니, 디폴트 2000개의 샘플 문서와 5초 절삭타임아웃을 가진다. 컨트롤은 이런 부분을 설정하는 부분이며, 하나의 필드를 기준으로 하여 샘플의 다양성을 좀더 부여할 수도 있다.[sample_diversity]

중요한 것은 컨트롤보다는 버티스와 커넥이다. 가령 이렇게 생각해보자, 버티스가 1, 커넥이 9인 경우와 버티스가 9, 커넥이 1인 경우, 결과가 많이 다를까? 같을까?

정답은 거의 같다. 이다. 이게 왜그러냐면, 커넥은 결국 첫번째 버티스에서 확장되어 정점을 가져가는 개념이기때문에, 하나의 질의문에 버티스가 1 커넥이 9라면 결국 검색어에 직접적인 결과가 나타나게 될 것이고, 버티스가 9 커넥이 1이라면 하나의 질의문에 대한 첫번째 직접적인 버티스가 9, 간접적인 단어는 1개만 나타나게 될 것이다. 결국에 커넥과 버티스를 한쪽을 극단적으로 가져가게 되면, 결국 직접적인 데이터밖에 추출할 수 없는 구조의 형태이다.

이만, 절삭하고 바로 쿼리를 보자.

POST dmap_map_mgr_news_tbl/_graph/explore
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "feat": {
              "query":"경제",
              "operator": "or"
            }
          }
        }
      ],
      "minimum_should_match": 1,
      "filter": {
        "range": {
          "provdDe": {
            "gte": 20191101,
            "lte": 20191131
          }
        }
      }
    }
  },
  "controls": {
    "use_significance": true,
    "sample_size": 2000,
    "timeout": 5000
  },
  "connections": {
    "query": {
      "bool": {
        "filter": {
          "range": {
            "provdDe": {
              "gte": 20191101,
              "lte": 20191131
            }
          }
        }
      }
    },
    "vertices": [
      {
        "field": "feat",
        "size": 8,
        "min_doc_count": 3,
        "exclude": [
          "경제"
        ]
      }
    ]
  },
  "vertices": [
    {
      "field": "feat",
      "size": 4,
      "min_doc_count": 3,
      "exclude": [
        "경제"
      ]
    }
  ]
}

이것이 결국 내가 사용한 그래프 쿼리인데, 내용이 재미있다. 이 쿼리에는 여러 조건이 있다.


desc.

  • 기본적으로는 TF(term frequency)를 TF/IDF보다 줄이긴 하지만, 무시할 수는 없음
  • 추출 단어 size를 높여 많은 데이터를 받으면 특별한단어(significant terms)를 받을 확률을 올릴 수 있음
  • 기사를 대상으로 분석하기 때문에, 기사의 특성을 가지고 있음. 예를들면, 여행의 관한 기사는 여행지나 관련 정보는 많을 수 있지만, 날씨등의 이야기는 기사에 거론이 잘 안될 수 있음
  • 사용자 로그쪽을 함께 분석하기에 이 부분 보완이 될 가능성 있음
  • 샘플을 추출하는 형태이기때문에, 결과는 조금씩 달라질 수 있음

graph 형태 Mig. desc.

  • 직접적인 여행에 관련한 내용 추출보다 vertices(정점)의 홉을 늘려서 확장한 쪽으로 더 많은 결과를 받아오도록 질의 함

  • 직접적인 정점에 size를 높이고 확장쪽 정점에 size를 낮추면 > 상대적으로 일반적인 연관어가 나올 가능성이 높아짐

  • 직접적인 정점에 size를 낮추고 확장쪽 정점에 size를 높이면 > 상대적으로 특별한 연관어(crossdomain)가 나올 가능성이 높아짐

  • 요구 검토 사항은 crossdomain을 좀더 많이 받으면 하여 아래와 같이 설정 함

  1. 중복문서단어들을 제거함으로써 다양한 단어를 더 수용할 수 있도록 처리
  2. 직접적인 정점에서 size를 4, 간접적 정점에서 8로 확장된 쪽으로 결과를 많이 받을 수 있도록 유도
  • 직접적인 정점을 너무 낮춰버리면 확장 정점 또한 그 직접적 단어에서 확장되어 버리기 때문에, 오히려 일반적인 terms가 추출 됨
  1. 날짜범위를 최근 한달로 지정함으로써 좀더 최신현안에 좀더 초점을 맞춤

참조