일반적으로 오라클이나 MySQL 같은 관계형DB에서는 위 내용을 tree형 자료 구조에 인덱스에 따라서 row 그대로 저장한다. 만약 위 테이블에서 `fox`가 포함된 행들을 가져온다고 하면 인덱스 여부에 따라 다르겠지만 text를 한줄씩 찾아 내려가면서 fox가 있으면 가져오고 없으면 넘어갈 것이다.
이는 Like 검색 방식인데 데이터가 늘어날수록 검색해야할 대상으 늘어 시간이 오래 걸리고 row 내용을 모두 읽어야 하기 때문에 매우 느리다. ES에서는 이러한 전문검색을 효율적으로하기 위해 위 데이터를 다음과 같이 역 인덱스 방식으로 만들어 저장한다.

ES에서는 추출된 각 키워드를 term이라고 부른다. 이렇게 역 인덱스 방식으로 구성되어 있으면 해당 term을 포함하고 있는 도큐먼트의 id를 바로 얻어올 수 있다. 이렇게 데이터가 저장될 때 역 인덱스로 데이터가 저장되는 과정을 색인한다고 표현한다.
ES에 저장되는 도큐넌트는 모든 문자열 필드 별로 역 인덱스를 생성한다.
ES는 문자열 필드가 저장될 때 데이터에서 검색어 토큰을 저장하기 위해 여러 단계의 처리 과정을 거친다. 이런 전체 과정을 텍스트 분석이라고하고 이 과정을 처리하는 기능을 애널라이저라고 한다. 애널라이저는 0~3개의 캐릭터 필터와 1개의 토크나이저, 0~n개의 토큰 필터로 이루어진다.

텍스트 데이터가 입력되면 가장 먼저 필요에 따라 전체 문장에서 특정 문자를 대치하거나 제거하는데 이 과정을 담당하는 기능이 캐릭터 필터이다.
다음으로 문장에 속한 단어들을 텀 단위로 하나씩 분리해 내는 처리 과정을 거치는데 이 과정을 담당하는 기능이 토크나이저이다. 토크나이저는 반드시 1개만 적용가능하다.
다음으로 분리된 텀들을 하나씩 가공하는 과정을 거치는데 이 과정을 담당하는 기능이 토큰 필터이다.
토큰 필터의 예시로는 대문자 -> 소문자 변경, 불용어 제거(a, an, the ..), 문법상 변형된 단어 변환 (ing 제거, s 제거), 동의어 추가 등이 있다.
ES에서는 분석된 문장을 API를 이용해서 확인할 수 있다.
토크나이저는 tokenizer, 토큰 필터는 filter 항목의 값으로 입력하면 된다. 토크나이저는 하나만 적용되기 때문에 바로 입력하고, 토큰필터는 여러개를 적용할 수 있기 때문에 배열 형식으로 입력한다.
GET _analyze
{
"text": "The quick brown fox jumps over the lazy dog",
"tokenizer": "whitespace",
"filter": [
"lowercase",
"stop",
"snowball"
]
}
위와 같은 데이터를 주어진 토크나이저와 필터를 적용하여 입력하면 처리된 데이터 결과를 확인할 수 있다. 여러 토큰 필터를 입력할 때는 순서가 중요하며 순서에 따라 결과가 달라진다.
애널라이저는 API에서 analyzer 항목으로 적용해서 사용이 가능하다. ES에서 사전 정의되어 바로 사용 가능한 애널라이즈도 있는데 대표적으로 위 예시를 조합한 snowball 애널라이저이다.
아래 예시는 위 예시와 같다.
GET _analyze
{
"text": "The quick brown fox jumps over the lazy dog",
"analyzer": "snowball"
}
인덱스에 애널라이저는 아래 예제와 같이 지정한다. 매핑에 대해서는 추후 더 자세히 설명한다.
PUT my_index2
{
"mappings": {
"properties": {
"message": {
"type": "text",
"analyzer": "snowball"
}
}
}
}
이렇게 애널라이저가 적용된 message 필드에 jump가 포함된 데이터를 삽입하면 match 쿼리로 jump, jumping, jumps 중 어떤 값으로 검색해도 같은 결과가 나타난다. (토큰 필터로 인해 역 인덱스에 jump로 저장)
ES에서 제공하는 쿼리 중에는 term 쿼리가 있다. match 쿼리와 문법은 유사하지만 term 쿼리에 입력한 검색어는 애널라이저를 적용하지 않고 그대로 일치하는 텀을 찾는다. 따라서 위 예시에서 jumps, jumping으로 검색하면 결과가 나타나지 않고 jump로 검색해야 결과가 나타난다.
사용자 정의 애널라이저는 인덱스 settings의 "index" : {"analyzer"} 부분에 정의한다.
생성한 다음에는 해당 인덱스에서 GET 또는 POST 명령으로 사용이 가능하다. 다음은 특정 인덱스에 my_custom_analyzer라는 이름의 애널라이저를 추가하는 예제이다.
PUT my_index3
{
"settings": {
"index": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"filter": [
"lowercase",
"stop",
"snowball"
]
}
}
}
}
}
}
토크나이저, 토큰필터의 경우에도 옵션을 지정하는 경우 사용자 정의 토크나이저, 토큰필터를 추가해야 한다. 다음은 stop 토큰필터에 "brown"을 불용어로 적용한 my_stop_filter 사용자 정의 토큰필터를 생성하고 이것을 애널라이저에 적용한 예제이다.
PUT my_index3
{
"settings": {
"index": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"filter": [
"lowercase",
"my_stop_filter",
"snowball"
]
}
},
"filter": {
"my_stop_filter": {
"type": "stop",
"stopwords": [
"brown"
]
}
}
}
}
}
}
애널라이저를 실제 인덱스에 입력할 데이터에 적용하려면 settings 부분에서 만든 애널라이저를 mappings의 text 필드졀로 지정한다. 앞에서 만든 my_custom_analyzer를 message 필드에 적용하는 법은 다음과 같다.
PUT my_index3
{
"settings": {
"index": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "whitespace",
"filter": [
"lowercase",
"my_stop_filter",
"snowball"
]
}
},
"filter": {
"my_stop_filter": {
"type": "stop",
"stopwords": [
"brown"
]
}
}
}
}
},
"mappings": {
"properties": {
"message": {
"type": "text",
"analyzer": "my_custom_analyzer"
}
}
}
}
이제 my_index에 message 필드에 입력되는 값은 위에 지정된 커스텀 애널라이저가 적용된다. my_index의 message 필드에 값을 입력하고 검색해보면 brown은 불용어 처리가 되어 검색되지 않는 것을 확인할 수 있다.
색인된 도큐먼트의 역인덱스 내용을 확인할 때는 도큐먼트 별로 _termvectors API를 이용해서 확인이 가능하다. GET <인덱스>/_termvectors/<도큐먼트id>?fields=<필드명> 형식으로 사용한다.
다음은 앞에서 입력한 my_index3/_doc/1 도큐먼트의 message 필드를 확인하는 예제이다.
GET my_index3/_termvectors/1?fields=message