DSL이란 Domain Specific Language 으로 JSON에 기반한 질의입니다. ES에서의 DSL은 데이터베이스의 SQL문과 동일하다고 이해하면 쉽습니다. 사용자가 원하는 데이터를 추출하기 위한 질의 언어입니다.


아래는 Elastic search에 질의를 하여 원하는 데이터를 추출하기 위한 DSL 예시입니다. 기본적으로 질의를 위해선 아래와 같이 "query" 속성을 사용합니다.

GET /조회할 인덱스명/_search/ 
{
  "query": { 
    ...
  }
}

Query VS Filter

DSL 기능이 어떤게 있는지 설명에 앞서 query와 filter간 차이점을 먼저 설명합니다.

기본적으로 Elastic search는 일치하는 검색 결과의 관련성을 점수 별로 정렬하여 각 문서가 쿼리와 얼마나 잘 일치하는지 측정합니다. 

관련성 점수는 소수점 숫자이며 검색 API의 _score 메타 필드에 반환됩니다. _score가 높을수록 문서의 관련성이 높아집니다. 각 쿼리 유형은 관련성 점수를 다르게 계산할 수 있지만 _score 계산은 query나 filter 문에서 실행되는 것에 따라 달라집니다.

Query

query문은 "이 문서가 이 쿼리 절과 얼마나 잘 일치합니까?"라는 질문에 대답합니다. 문서가 일치하는지 여부를 결정하는 것 외에도 query문은 _score 메타 필드에서 관련성 점수를 계산합니다.

Filter

filter문은 query문과 같이 "이 문서 가 이 쿼리 절과 일치합니까?"라는 질문에 대답합니다. 차이점은 score를 계산하지 않고 간단하게 예 또는 아니요 로 계산합니다. filter문은 주로 구조화 된 데이터를 필터링하는 데 사용됩니다. 예를 들어, "등록 시간이 2018년에서 2019년 사이에 있는 데이터 나 데이터의 상태 값이 삭제가 안 된 데이터" 와 같이 문서의 score가 필요없는 데이터 형태를 필터링할 때 사용됩니다. 또한 Elasticsearch는 filter 문을 사용하게 되면 자동으로 캐싱하여 성능을 향상 시킵니다.

score를 계산하지 않기 때문에 query보다 검색이 빠릅니다.

아래는 query와 filter를 비교한 표입니다.



QueryFilter
검색 결과관련성Yes or No
검색 범위전문 검색주어진 질의에 해당하는 정확한 값
캐시여부NoYes
관련성 점수 계산YesNo


예시

GET /test-index/_search 
{
  "query": {
    "bool": { (1)      
      "must": [{
        "match": {
          "title": "Search"
        }
      }, {
        "match": {
          "content": "Elasticsearch"
        }
      }],
      "filter": [ (2)
        {
        "term": {
          "status": "published"
        }
      }, {
        "range": {
          "publish_date": {
            "gte": "2015-01-01"
          }
        }
      }]
    }
  }
}

1 bool 하위 두 개의 match 절은 query문을 사용하므로 각 문서가 얼마나 잘 일치하는지 score를 매기는 데 사용됩니다. 

filter 하위의 term과 range 절은 필터 문에서 사용됩니다. 위 조건에 일치하는 문서는 score에 영향을 미치지 않고 결과를 반환합니다.


검색하고자 하는 용도에 따라 query와 filter를 유연하게 사용해야 좋은 성능을 낼 수 있습니다.

Query

용어들을 설명하기에 앞서 "여러개의 물건들" 이라는 문장을 형태소 분석기에 의해 아래와 같이 쪼개졌다고 가정합니다.

GET /test-index/_analyze 
{
  "analyzer": "analyzer_mixed",
  "text": "여러개의 물건들"
} {
  "tokens": [{
    "token": "여러",
    "start_offset": 0,
    "end_offset": 2,
    "type": "MM",
    "position": 0
  }, {
    "token": "개",
    "start_offset": 2,
    "end_offset": 3,
    "type": "NNB",
    "position": 1
  }, {
    "token": "물건",
    "start_offset": 5,
    "end_offset": 7,
    "type": "NNG",
    "position": 2
  }, {
    "token": "물건들",
    "start_offset": 5,
    "end_offset": 8,
    "type": "NNG",
    "position": 2
  }]
}

term

term은 형태소 분석기에 의해 쪼개진 토큰들을 기반으로 동작합니다. 즉, term은 주어진 질의문과 저장된 형태소의 토큰이 정확하게 일치하는 문장을 찾습니다.

GET /test-index/_search 
{
  "query": {
    "term": {
      "name": "여러"
    }
  }
}
// 토큰 중에 "여러"가 있으므로 검색 결과 있음 

GET /test-index/_search 
{
  "query": {
    "term": {
      "name": "여러개"
    }
  }
}
// 토큰 중에 "여러개"가 없고 "여러"와 "개"로 나눠져 있으므로 검색 결과 없음


이러한 이유로 검색하고자 하는 데이터 타입이 텍스트 필드라면 term 쿼리를 사용하는 것을 지양하고 match 쿼리를 사용하는 것이 좋습니다.

terms

term의 경우, 질의문이 1개만 가능하지만 terms는 여러 개의 질의문을 사용할 수 있습니다.

GET /test-index/_search
{
  "query": {
    "terms": {
      "name": ["여러", "개"]
    }
  }
}

match

기본 동작은 term과 동일하게 형태소 분석기에 의해 쪼개진 토큰들을 기반으로 동작합니다. 차이점은 match는 주어진 질의를 형태소 분석기를 거쳐 쪼갠 다음 조회를 합니다. 예를 들어, "여러개" 라는 값이 들어 왔다면 형태소 분석기에 의해 "여러", "개"로 나눠지고 토큰을 조회를 하게 됩니다. 이 때, 1개라도 존재하는 토큰이 있으면 결과를 반환합니다. 즉, 형태소 분석기에 의해 쪼개진 질의들을 or 조건으로 검색하게 됩니다. 

GET /test-index/_search 
{
  "query": {
    "match": {
      "name": "여러개"
    }
  }
}
// "여러개" 라는 질의를 형태소 분석기를 통해 "여러", "개"로 쪼갠 후, 검색. 
GET /test-index/_search 
{
  "query": {
    "match": {
      "name": {
        "query": "주름원",
        "operator": "and"
      }
    }
  }
}
// operator: "and"를 명시하면 쪼개진 질의문들이 전부 일치해야만 됨. 이 때, 중괄호가 한 번 더 들어가게 됨

multi_match

여러 필드에 단일 질의문을 검색할 때 사용합니다.

GET /test-index/_search
{
  "query": {
    "multi_match": {
      "fields": ["name", "category"],
      "query": "원피스"
    }
  }
}

match_phase

match_phase는 보통 문장을 검색할 때 사용합니다. match와 동일하게 형태소 분석기에 의해 토큰으로 쪼개집니다. 이 때, 차이점은 match의 경우는 순서와 상관없이 보통 1개 이상 일치하는 토큰이 있으면 검색 결과를 반환하는 반면에 match_phase는 입력된 질의와 저장된 토큰의 순서가 정확하게 일치해야 됩니다.

GET /test-index/_search
{
  "query": {
    "bool": {
      "must": [{
        "match_phrase": {
          "content": "여러 개"
        }
      }]
    }
  }
}
// "여러"와 "개"가 존재하고 토큰의 순서도 맞으므로 결과 반환 


GET /test-index/_search 
{
  "query": {
    "bool": {
      "must": [{
        "match_phrase": {
          "content": "물건 여러 개"
        }
      }]
    }
  }
}
// 저장된 토큰의 순서는 "여러", "개", "물건" 순으로 순서가 맞지 않아 결과 반환 X 
GET /test-index/_search
{
  "query": {
    "bool": {
      "must": [{
        "match_phrase": {
          "content": "내 물건"
        }
      }]
    }
  }
}
// "내"라는 토큰이 저장되어 있지 않아 결과 반환 X

Bool

bool 쿼리는 다른 쿼리들을 조합하여 결과와 score들을 결합하거나 동작을 변경합니다. 즉, bool 하위의 여러 쿼리들을 결합하여 결과를 낼 때 사용합니다. bool은 쿼리와 필터에서의 동작이 상이합니다. 쿼리로 사용할 때는 score가 결합되어 일치하는 절이 많을 수록 더 좋습니다.

bool의 기본 쿼리는 must, must_not, should가 있습니다.

  • must:  모든 필터가 매치되어야 함 (and)
  • filter: 위에서 설명한 filter와 동작은 동일. score를 무시하고 결과가 캐싱됨
  • must_not: 문사거 필터에 매치되지 않아야 함 (not). 필터 절에서 실행되므로 score가 무시되고 캐싱이 고려. score가 무시되므로 score는 0으로 반환.
  • should: 최소 minimum_should_match개의 필터에 매치되어야 함 (or)
    • minimum_should_match: should에서 최소 match 개의 수 (기본값 1 - must가 함께 사용되면 기본값 0)
GET /test-index/_search
{
  "query": {
    "bool": {
      "must": {
        "term": {
          "user": "kimchy"
        }
      },
      "filter": {
        "term": {
          "tag": "tech"
        }
      },
      "must_not": {
        "range": {
          "age": {
            "gte": 10,
            "lte": 20
          }
        }
      },
      "should": [{
          "term": {
            "tag": "wow"
          }
        },
        {
          "term": {
            "tag": "elasticsearch"
          }
        }
      ],
      "minimum_should_match": 1,
    }
  }
}

query_string

syntax를 강력하게 체크하는 파서를 사용하여 제공된 쿼리 문자열을 기반으로 문서를 반환

이 쿼리는 syntax를 사용하여 AND 또는 NOT과 같은 연산자를 기반으로 제공된 쿼리 문자열에 대해 질의문을 분석하고 분할합니다. 그런 다음 일치하는 문서를 반환하기 전에 앞에서 분석하고 분할한 각 텍스트를 독립적으로 분석합니다. query_string 조회를 사용하여 와일드 카드, 다중 필드 검색 등을 포함하는 복잡한 검색을 작성할 수 있습니다. 여러 방면에서 좋지만 쿼리의 유효성 검사는 엄격하고  쿼리 문자열에 유효하지 않은 구문이 포함 된 경우 오류를 반환합니다.

잘못된 구문에 대해서는 오류를 반환하므로 검색 창에 query_string 검색어를 사용하지 않는 것이 좋습니다.

쿼리 syntax를 지원할 필요가 없으면 match 쿼리를 사용하는 것이 좋습니다. 만약 쿼리 syntax의 기능이 필요한 경우에는 덜 엄격한 simple_query_string 쿼리를 사용하는 것이 좋습니다.


GET /_search
{
  "query": {
    "query_string": {
      "query": "(new york city) OR (big apple)",
      "default_field": "content"
    }
  }
}

다음 검색을 실행하면 query_string 쿼리가 (new york city) 와 (big apple) 두 부분으로 나뉩니다. content 필드의 분석기는 일치하는 문서를 반환하기 전에 new york city와 big apple을 각각 토큰으로 변환합니다. 쿼리 syntax는 공백을 연산자로 사용하지 않으므로 new york city는 그대로 분석기에 전달됩니다.


query_string 은 아래와 같은 옵션을 가지고 있습니다.

  • query: 검색 하고자 하는 질의
  • default_field: query의 적용 대상 필드. 정의되지 않으면 인덱스의 모든 필드에 적용
  • allow_leading_wildcard: 기본값으로 true이며, true일 경우, query string의 첫 문자열에 *나 ?이 올 수 있음
  • analyze_wildcard: 기본값으로 false이며 true일 경우, wildcard terms을 분석

  • fields: 어레이 필드로 여러 필드에 query string을 적용할 수 있음

simple_query_string

query_string에 비해 좀 더 유연한 parser를 사용하여 제공된 쿼리 문자열을 기반으로 문서를 반환

이 쿼리는 simple syntax를 사용하여 제공된 쿼리 문자열을 특수 연산자를 기반으로 구성된 질의문을 분석하고 분할합니다. 그런 다음 쿼리는 일치하는 문서를 반환하기 전에 앞에서 분석하고 분할한 각 텍스트를 독립적으로 분석합니다. simple_query_string은 query_string 쿼리보다 제한적이지만 잘못된 syntax에 대한 오류를 반환하지 않고 쿼리 문자열의 유효하지 않은 부분을 무시합니다.


GET /_search
{
  "query": {
    "simple_query_string": {
      "query": "\"fried eggs\" +(eggplant | potato) -frittata",
      "fields": ["title^5", "body"],
      "default_operator": "and"
    }
  }
}

query_string의 옵션과 대부분 유사합니다.

필터

필터 쿼리는 사실상 위의 bool에서 설명이 됐습니다. 현재 elastic search에서는 filtered 문법이 사라지고 bool 쿼리를 사용하도록 변경됐습니다.

## ES 7.4 기준으로 더이상 사용하지 않음
GET /_search
{
  "query": {
    "filtered": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "filter": {
        "term": {
          "status": "published"
        }
      }
    }
  }
}
 ## 아래와 같이 사용해야함 GET /_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "filter": {
        "term": {
          "status": "published"
        }
      }
    }
  }
}


'DB > Elasticsearch' 카테고리의 다른 글

[Elasticsearch] DSL 살펴보기  (0) 2019.12.01


test 테이블의 데이터

test1
abcd
1111
1234


array로 변경

select array_agg(test1) from test {abcd,1111,1234}

string으로 변경

select string_agg(test1, ',') from test abcd,1111,1234


array 데이터를 각 로우로 변경

unnest(array타입)


-- 예시
select unnest(ARRAY[1,2])


1
2
(2 rows)

array 타입에 데이터 추가

array_append(array, 값)


-- 예시
array_append(ARRAY[1,2], 3)


{1,2,3}

array 타입끼리 협차기

array_cat(array, array}


-- 예시
array_cat(ARRAY[1,2], ARRAY[3,4])


{1,2,3,4}

array에서 string(단일컬럼)으로 변경

array_to_string(array, 구분자, [NULL 값 대체 구분자])


-- 예시
array_to_string(ARRAY[1, 2, 3, NULL, 5], ',', '*')


1,2,3,*,5

string을 array로 변경

string_to_array(string, 구분자, [null로 변경할 값])


-- 예시
string_to_array('xx~^~yy~^~zz', '~^~', 'yy')
{xx,,zz}


샤딩(sharding)과 파티셔닝(partitioning)의 차이

파티셔닝이란 퍼포먼스(performance), 가용성(availability) 또는 정비용이성(maintainability)를 목적으로 논리적인 데이터 엘리먼트들을 다수의 table로 쪼개는 행위를 뜻하는 일반적인 용어입니다.

샤딩은 수평 파티셔닝(horizontal partitioning)과 동일합니다. 데이터베이스를 샤딩하게 되면 기존에 하나로 구성될 스키마를 다수의 복제본으로 구성하고 각각의 샤드에 어떤 데이터가 저장될 지를 샤드 키를 기준으로 분리합니다. 

수평 파티셔닝 (horizontal partitioning) = 샤딩


위 예시를 보면 1 ~ 5 번 고객의 정보는 하나의 샤드에 저장하고 6 ~ 10 번 고객의 정보는 다른 샤드에 저장하기로 한 예시 입니다. DBA는 데이터 엑세스 패턴과 저장 공간 이슈(로드의 적절한 분산 , 데이터의 균등한 저장)를 고려하여 적절한 샤드 키를 결정하게 됩니다.

수직 파티셔닝 (vertical partitioning)


수직 파티셔닝(vertical partitioning)은 하나의 테이블에 저장된 데이터들을 공간이나 퍼포먼스의 이유로 다수의 테이블로 분리하는것을 말합니다. 이러한 작업을 하는 이유는 DB의 3정규화(Normalization)로 접근하면 편합니다.

'DB' 카테고리의 다른 글

샤딩(sharding), 파티셔닝(partitioning)  (0) 2018.12.23
[DB] ETL이란  (0) 2018.12.22
[DB] CDC란  (0) 2018.12.22
[DB]Connection Pool  (0) 2017.02.11
[SQL] WHERE절에서 IF문처럼 AND 사용  (0) 2017.02.02
[DB] 클러스터  (0) 2016.11.18

ETL은 Extract, Transform, Load 의 앞글자를 딴 용어입니다. 즉 데이터를 추출, 변환, 적재를 한다는 것입니다. 내용은 그렇게 어렵지가 않습니다.

예를 들어, calendar라는 테이블에 년/월/일/시/분/초 형태로 각 컬럼이 존재합니다. 이러한 데이터를 사용하여 통계를 내는 어떤 프로그램을 실행하려고 확인 했더니 해당 프로그램은 년월일/시분초 와 같은 컬럼형태를 요구하고 있을 때 작업을 하는 것을 ETL이라 합니다.

예시

Extract

대상이 되는 calendar 테이블에서 년/월/일/시/분/초 형태의 데이터를 전부 추출합니다.

Transform

추출한 데이터를 요구하는 형태인 년월일/시분초 형태로 변경을 합니다.

Load

변경이 된 데이터를 새로운 테이블에 적재합니다.

요약

간단하게 위와 같은 단계를 거치는 것이 ETL이라 합니다. ETL은 저장된 데이터를 변형하여(요구사항에 맞게) 다른 곳으로 이동하는 것 이라 볼 수 있습니다. 위 예제처럼 컬럼 개수를 변형할 수도 있고 데이터의 형태나 컬럼 개수를 변형하지 않는 작업이 될수도 있습니다. 예를 들어 MSSQL을 사용하다가 PostgreSQL로 데이터를 이전하고 싶을 경우, 데이터의 형태와 컬럼 개수는 유지하면서 테이블의 스키마를 조금 변형하는 작업이 될 수도 있습니다.

'DB' 카테고리의 다른 글

샤딩(sharding), 파티셔닝(partitioning)  (0) 2018.12.23
[DB] ETL이란  (0) 2018.12.22
[DB] CDC란  (0) 2018.12.22
[DB]Connection Pool  (0) 2017.02.11
[SQL] WHERE절에서 IF문처럼 AND 사용  (0) 2017.02.02
[DB] 클러스터  (0) 2016.11.18

Change Data Capture의 약어로 마지막으로 추출한 이후 변경된 데이터만 골라내는 기술을 의미합니다. 흔히 데이터 백업이나 통합 작업을 할 경우 방대한 데이터를 다뤄야 하는데 원본 소스 데이터 가운데 최근 변경된 데이터들만 골라 다른 시스템으로 옮기게 되면 시스템 로드도 줄이고 전체적인 작업 생산성을 향상시킬 수 있습니다.  특히 한 시스템에 있는 대량의 데이터를 정기적으로 추출해 다른 시스템으로 이동하는 데이터 통합이나 데이터 웨어하우스 업무의 경우 CDC 기술을 이용하면 데이터를 추출, 이동하는 시간을 크게 줄일 수 있습니다. 또한 24시간 운영해야 하는 필수적인 업무 시스템의 경우 CDC 기술을 이용하면 다운타임 없이 실시간 백업과 데이터 통합이 가능합니다.


'DB' 카테고리의 다른 글

샤딩(sharding), 파티셔닝(partitioning)  (0) 2018.12.23
[DB] ETL이란  (0) 2018.12.22
[DB] CDC란  (0) 2018.12.22
[DB]Connection Pool  (0) 2017.02.11
[SQL] WHERE절에서 IF문처럼 AND 사용  (0) 2017.02.02
[DB] 클러스터  (0) 2016.11.18

+ Random Posts