검색 엔진 Search/Elastic Search

[Basic] Elasticsearch 간단한 인덱스 구성하기 실습 - Mapping, Analysis, Similarity, Setting

지난 글들에서 간단하게 살펴본 내용을 바탕으로 오늘은 직접 샘플 인덱스를 구축해보려고 합니다.

간단한 필드 구성을 가진 인덱스를 생성하면서, 언급했던 일부 인덱스 모듈 내용을 추가해봅시다.

 

Elasticsearch 시리즈는 7.10 버전을 기본으로 설명합니다. 필요하다면 8.0 이후의 버전 내용을 추가로 설명합니다.

 

Mapping

유저에 관련된 필드 "age", "level", "name"를 가진 "sample-user-index"를 생성합니다.

각각의 필드에 대해 유형을 정의할 수 있습니다. integer 유형은 말 그대로 32비트 정수를 의미합니다.

 

keyword 와 text 유형은 둘다 텍스트에 관한 유형이지만, 전자는 term level search, 후자는 full-text search를 지원한다는 점이 다릅니다.

(아직 다루지 않은 검색에 관한 차이라서 서로 다른 로직으로 검색이 이루어진다고만 이해하고 넘어가도 됩니다!)

PUT /sample-user-index
{
  "mappings": {
    "properties": {
      "age": { "type": "integer" },  
      "level": { "type": "keyword" }, 
      "name": { "type": "text" }     
    }
  }
}

 

만약 필드 중 저장(store)은 하지만, 색인화(index)시키거나 검색(search)되지 않아도 되는 필드가 있다면 다음과 같이 특정 필드만 "index" 파라미터에 대해 "false"로 명시하면 됩니다.

PUT /sample-user-index
{
  "mappings": {
    "properties": {
      "age": { 
      	"type": "integer",
      	"index": false 
      },  
      "level": { "type": "keyword" }, 
      "name": { "type": "text" }     
    }
  }
}

 

이 외에도 적용할 수 있는 다양한 설정들이 있습니다. 아래는 그 중 자주 사용하는 몇몇 파라미터입니다.

"text" 유형 필드를 색인하거나 검색할 때 텍스트 분석에 사용되는 분석기를 지정합니다.

"text" 유형 필드를 색인할 때와 별도로 검색할 때 텍스트 분석에 사용되는 분석기를 따로 지정할 수 있습니다.

다중 필드를 생성할 때 사용합니다.

동일한 필드를 다른 목적으로 다른 방식으로 색인화하는 것이 유용한 경우가 많습니다.

예를 들어, 하나의 필드에 대해 "text" 유형과 "keyword" 유형으로 각각 저장할 수 있습니다.

"date" 유형의 필드 등에 대해 "yyyy-MM-dd"와 같은 저장 형식을 지정할 수 있습니다.

기본적으로 null 값은 색인하거나 검색할 수 없습니다.

필드가 null (또는 빈 배열 또는 null 값의 배열)로 설정되면 해당 필드에 값이 없는 것처럼 취급됩니다.

하지만, null_value 파라미터를 사용하면 명시적 null 값을 지정된 값으로 대체하여 색인 및 검색이 가능하도록 할 수 있습니다.

전체 인덱스 설정으로도 유사도로 사용할 방법을 지정할 수 있지만, 인덱스 자체의 유사도와 별도로 특정 필드에 대해서는 다른 유사도를 사용할 수 있습니다.

 

Analysis

앞서 만들어두었던 "name" 필드의 유형이 "text" 였습니다. ES에서는 full-text 검색을 위해 해당 유형의 필드에 한해 텍스트 분석을 진행합니다.

이때의 검색은 정확히 일치하는 결과만 반환하는 것이 아니라 검색 쿼리와 관련된 모든 결과를 반환합니다.

 

텍스트 분석을 위해 사용될 분석기는 ES에서 기본 제공하는 것들도 있지만 사용자가 커스텀할 수도 있습니다.

기본 제공 분석기가 사용자의 요구 사항을 충족하지 못하는 경우 적절한 조합을 사용하는 사용자 지정 분석기를 만들 수 있습니다. 이때, 다음과 같은 조합으로 만들 수 있습니다.

 

tokenizer는 ES에서 기본으로 제공하는 Standard 나 Whitespace 도 많이 쓰지만, 한국어 토크나이저인 nori-tokenizer를 주로 씁니다.

이 외에도 N-Gram이나 Edge N-Gram 을 토큰으로 뽑을 수 있는 토크나이저도 사용할 수 있습니다. 

토크나이저는 1개가 필수로 필요하지만, 다른 항목은 아닙니다.

 

그러나, token filter를 통해 토큰 수정(lowercase 등), 토큰 삭제(stopwords), 토큰 추가(synonyms)의 적용을 할 수 있어 자주 사용됩니다.

character filter 에서는 지정된 문자열의 모든 항목을 지정된 대체 항목으로 대체할 수 있는 mapping character filter가 주로 사용됩니다.

 

다음은 기본으로 제공하는 Standard TokenizerSynonym_graph token filter 를 사용하여 커스텀 분석기를 만들고,

"text" 필드 "name"에 대해 색인 analyzer와 검색 analyzer를 각각 지정한 예제입니다.

PUT /sample-user-index
{
  "mappings": {
    "properties": {
      "age": { 
      	"type": "integer",
      	"index": false 
      },  
      "level": { "type": "keyword" }, 
      "name": { 
      	"type": "text",
        "analyzer": "standard",
        "search_analyzer": "standard_synonym"
       }     
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "filter": {
          "synonym": {
            "updateable": "true",
            "expand": "true",
            "type": "synonym_graph",
            "synonyms_path": "analysis/synonym.txt",
            "lenient": "true"
          }
        },
        "analyzer": {
          "standard": {
            "filter": [
              "lowercase"
            ],
            "type": "custom",
            "tokenizer": "standard"
          },
          "standard_synonym": {
            "filter": [
              "lowercase",
              "synonym"
            ],
            "type": "custom",
            "tokenizer": "standard"
          }
        }
      }
    }
  }
}

 

Similarity & Setting

Analysis 외에도 인덱스 생성시 인덱스에 대한 다양한 설정을 정의할 수 있습니다.

예를 들어 아래와 같이, 인덱스 내 기본 유사도로 쓰일 유사도를 명시하거나, 인덱스의 샤드 또는 레플리카 크기도 설정할 수 있습니다.

PUT /sample-user-index
{
  "mappings": {
    "properties": {
      "age": { 
      	"type": "integer",
      	"index": false 
      },  
      "level": { "type": "keyword" }, 
      "name": { 
      	"type": "text",
        "analyzer": "standard",
        "search_analyzer": "standard_synonym"
       }     
    }
  },
  "settings": {
    "index": {
      "number_of_shards": "1",
      "number_of_replicas": "2"
      "similarity": {
        "default": {
          "type": "BM25"
        }
      },
      "analysis": {
        "filter": {
          "synonym": {
            "updateable": "true",
            "expand": "true",
            "type": "synonym_graph",
            "synonyms_path": "analysis/synonym.txt",
            "lenient": "true"
          }
        },
        "analyzer": {
          "standard": {
            "filter": [
              "lowercase"
            ],
            "type": "custom",
            "tokenizer": "standard"
          },
          "standard_synonym": {
            "filter": [
              "lowercase",
              "synonym"
            ],
            "type": "custom",
            "tokenizer": "standard"
          }
        }
      }
    }
  }
}

 

인덱스 설정에는 이외에도 많은 인덱스 정의시 명시된 값을 바꿀 수 없는 static 설정들과 dynamic 설정들이 존재합니다.

필요시마다 추가로 각 설정들을 익히는 것을 추천합니다!

 

마무리

오늘은 간단하게 필드 "age", "level", "name"를 가진 "sample-user-index"를 생성해보았습니다.

다양한 필드 매핑과 분석기를 중심으로 인덱스를 직접 생성하며 실습해보았는데요!

 

다음 글부터는 해당 인덱스에 문서를 색인하고, 직접 정의한 분석기가 어떻게 작동하는지, 검색은 어떻게 수행하는지 차례대로 알아봅시다!

 

 

References

 

Mapping | Elasticsearch Guide [7.10] | Elastic

Mapping is the process of defining how a document, and the fields it contains, are stored and indexed. For instance, use mappings to define: which string fields should be treated as full text fields. which fields contain numbers, dates, or geolocations. th

www.elastic.co

 

 

Text analysis | Elasticsearch Guide [7.10] | Elastic

Text analysis is the process of converting unstructured text, like the body of an email or a product description, into a structured format that’s optimized for search. When to configure text analysisedit Elasticsearch performs text analysis when indexing

www.elastic.co

 

 

Index modules | Elasticsearch Guide [7.10] | Elastic

The number of shards are limited to 1024 per index. This limitation is a safety limit to prevent accidental creation of indices that can destabilize a cluster due to resource allocation. The limit can be modified by specifying export ES_JAVA_OPTS="-Des.ind

www.elastic.co