本記事は Elasticsearch 入門記事の第3回「Analyzer の設定」です。
その他の Elasticsearch の使い方は以下の記事をご覧ください。
- 【Elasticsearch 入門1】Elasticsearch とは (概要/できること/検索方法)
- 【Elasticsearch 入門2】マッピング管理とテンプレート
- 【Elasticsearch 入門3】Analyzer の設定 (日本語検索、トークナイズ) ←イマココ
- 【Elasticsearch 入門4】集計・分類 (Aggregations)
- 【Elasticsearch 入門5】Dynamic index settings の変更
Analyzer とは
Analyzer は以下の3つの要素によって構成されます。
Analyzer の要素 | 説明 |
---|---|
Char Filter | ドキュメントを前処理 (加工、フィルタリング) |
Tokenizer Filter | ドキュメントをトークン(単語)に分割 |
Token filter | トークン (単語) のフィルタリング |

Char Filter の種類 | 説明 | 例 |
---|---|---|
HTML Strip Character Filter | HTML タグを除去 | <p>タグを除去 <p>Elasticsearch</p> → Elasticsearch |
Mapping character filter | マッピングを作成 | アラビア数字をラテン数字にマッピング [٠١٢٣٤٥٦٧٨٩] → [0123456789] |
Pattern replace character filter | 正規表現で置換 | ハイフンをアンダースコアに置換 [123-456-789] → [123_456_789] |
Char Filter の使い方
GET /_analyze { "char_filter" : ["html_strip"], "text" : "<p>Elasticsearch is simple</p>" }
"token" : """Elasticsearch is simple""",
<p> タグが除去できました。
Tokenizer の種類 | 説明 | 例 |
---|---|---|
■単語指向分割 (形態素解析) Standard Tokenizer Letter Tokenizer Lowercase Tokenizer Whitespace Tokenizer UAX URL Email Tokenizer Classic Tokenizer Thai Tokenizer | 空白等で単語を分割 | Elasticsearch is simple → [Elasticsearch, is, simple] |
■N-gram 分割 (Partial Words) N-Gram Tokenizer Edge N-Gram Tokenizer | N 文字で単語を分割 | N-Gram: quick → [qu, ui, ic, ck]. Edge N-Gram: quick → [q, qu, qui, quic, quick] |
■構造化テキスト分割 Keyword Tokenizer Pattern Tokenizer Simple Pattern Tokenizer Char Group Tokenizer Simple Pattern Split Tokenizer Path Tokenizer | 一定規則で単語を分割 | /foo/bar/baz → [/foo, /foo/bar, /foo/bar/baz ] |
形態素解析には、主に次の2種類があります。
- 空白で分割
- 辞書/ラティスで分割
空白で分割
空白でドキュメント (文章) をトークン (単語) に分割する方法です。
Elasticsearch is simple --> [Elasticsearch], [is], [simple]
日本語の場合は、空白で文章が区切られないので、後述する「辞書/ラティス」で分割します。
辞書/ラティスで分割
- 辞書とは、単語と品詞の一覧です。
- ラティスとは、全ての単語の組み合わせをグラフにしたものです。

以下の2つのコストの合計が最も低い経路を選択します。
- 生起コスト:単語の出現しやすさ (例: 「アベック」より「カップル」の方がよく言う)
- 連接コスト:2つの単語の繋がりやすさ (動詞の後は格助詞が来ない [例: ドアを開ける"を"])
なお、辞書に載ってない単語の検索漏れが発生する欠点があります。
- 2-gram (bigram) の場合:quick → [qu, ui, ic, ck]
- 3-gram (trigram) の場合:quick → [qui, uic, ick]
N-gram は、辞書に載ってない単語でも検索できる一方で、検索ノイズが大きくなります。
(2-gram の場合、ice → [ic, ce] で quick → [qu, ui, ic, ck] がヒットするなど。)
Tokenizer の使い方
文字列を空白でトークナイズします。
GET /_analyze { "tokenizer": "whitespace", "text": "Elasticsearch is simple" }
"tokens" : [ { "token" : "Elasticsearch", "start_offset" : 0, "end_offset" : 13, "type" : "word", "position" : 0 }, { "token" : "is", "start_offset" : 14, "end_offset" : 16, "type" : "word", "position" : 1 }, { "token" : "simple", "start_offset" : 17, "end_offset" : 23, "type" : "word", "position" : 2 }
[Elasticsearch is simple] を [Elasticsearch], [is], [simple] の3つのトークンに分割できました。
Token Filter の種類 | 説明 | 例 |
---|---|---|
Lower case Token Filter | トークンを小文字に変換 | [Google] → [google] |
Stop Token Filter | ストップワードを設定 | [Elasticsearch is simple] → [Elasticsearch, simple] |
Stemmer Token Filter | ステミングを設定 | [swims], [swimming], [swimmer] → [swim] |
Synonym Token Filter | シノニムを設定 | [jump], [leap] → [jump] |
例:[Elasticsearch is simple] → [Elasticsearch, simple]
例:[swims], [swimming], [swimmer] → [swim]
例:[jump], [leap] → [jump]
Token filter の使い方
ストップワードで is をフィルタリングします。
GET /_analyze { "tokenizer": "standard", "filter": [ "stop" ], "text": "Elasticsearch is simple" }
"tokens" : [ { "token" : "Elasticsearch", "start_offset" : 0, "end_offset" : 13, "type" : "<ALPHANUM>", "position" : 0 }, { "token" : "simple", "start_offset" : 17, "end_offset" : 23, "type" : "<ALPHANUM>", "position" : 2 }
ストップワードのデフォルトの設定に従って、"is" がフィルタリングされています。
When not customized, the filter removes the following English stop words by default:
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stop-tokenfilter.html#analysis-stop-tokenfiltera
,an
,and
,are
,as
,at
,be
,but
,by
,for
,if
,in
,into
,is
,it
,no
,not
,of
,on
,or
,such
,that
,the
,their
,then
,there
,these
,they
,this
,to
,was
,will
,with
Analyzer の種類と一覧
Analyzer には以下の2種類があります。
Analyzer の種類 | 説明 |
---|---|
Built-in analyzer | Char Filter, Tokenizer, Token Filter が事前に定義されている |
Custom analyzer | Char Filter, Tokenizer, Token Filter を自分で定義する |
Elasticsearch に事前に組み込まれている Built-in analyzer の一覧は以下のとおりです。

Analyzer の設定を何もしない場合、Standard Analyzer を使用します。
GET /_analyze { "analyzer": "whitespace", "text": "Elasticsearch is simple" }
{ "token" : "Elasticsearch", "start_offset" : 0, "end_offset" : 13, "type" : "word", "position" : 0 }, { "token" : "is", "start_offset" : 14, "end_offset" : 16, "type" : "word", "position" : 1 }, { "token" : "simple", "start_offset" : 17, "end_offset" : 23, "type" : "word", "position" : 2 }
Built-in analyzer の設定
インデックス (built-in) の text フィールドに、Built-in analyzer (Whitespace analyzer) を設定してみます。
PUT built-in { "mappings": { "properties": { "text": { "type": "text", "analyzer": "whitespace" } } } }
Built-in analyzer のトークナイズ結果を確認
GET built-in/_analyze { "analyzer": "whitespace", "text": "Elasticsearch is simple" }
"tokens" : [ { "token" : "Elasticsearch", "start_offset" : 0, "end_offset" : 13, "type" : "word", "position" : 0 }, { "token" : "is", "start_offset" : 14, "end_offset" : 16, "type" : "word", "position" : 1 }, { "token" : "simple", "start_offset" : 17, "end_offset" : 23, "type" : "word", "position" : 2 }
空白単位でトークンを生成していることが確認できます。
設定した Built-in analyzer で検索
PUT built-in/_doc/1 { "text":"Elasticsearch is simple" }
GET built-in/_search { "query": { "match": { "text": "Elasticsearch" } } }
"hits" : [ { "_index" : "built-in", "_type" : "_doc", "_id" : "1", "_score" : 0.2876821, "_source" : { "text" : "Elasticsearch is simple"
空白単位の単語で検索できることが確認できます。
Custom analyzer の設定
以下のような Custom analyzer を作成してみます。
Analyzer の要素 | 構成 | やりたいこと |
---|---|---|
Char Filter | HTML strip character filter | ドキュメントから <p> タグを除去 |
Tokenizer | Whitespace tokenizer | ドキュメントを空白でトークン (単語) に分割 |
Token filter | Stop token filter Lowercase token filter | トークンから "This", "is" を除去 大文字のトークンを小文字にする |
インデックス (custom) の text フィールドに、Custom Analyzer (my_custom_analyzer) を設定します。
PUT custom { "settings": { "analysis": { "analyzer": { "my_custom_analyzer": { "type": "custom", "char_filter": "html_strip", "tokenizer": "whitespace", "filter": ["lowercase","stop"] } } } }, "mappings": { "properties": { "text": { "type": "text", "analyzer": "my_custom_analyzer" } } } }
Custom analyzer のトークナイズ結果を確認
POST custom/_analyze { "analyzer": "my_custom_analyzer", "text": "<p>This is Elasticsearch</p>" }
{ "tokens" : [ { "token" : "elasticsearch", "start_offset" : 11, "end_offset" : 24, "type" : "word", "position" : 2
Custom analyzer (my_custom_analyzer) で設定したとおり、HTML タグは消え、"This", "is" トークンは削除され、"Elasticsearch" トークンは小文字になっています。
設定した Custom analyzer で検索
PUT custom/_doc/1 { "text":"<p>Elasticsearch is simple</p>" }
GET custom/_search { "query": { "match": { "text": "elasticsearch" } } }
"hits" : [ { "_index" : "custom", "_type" : "_doc", "_id" : "1", "_score" : 0.2876821, "_source" : { "text" : "Elasticsearch is simple
"
Elasticsearch が小文字でも正しく検索できています。
kuromoji analyzer (日本語検索)
デフォルトの Standard Analyzer では、日本語をうまくトークンに分割できないため、日本語を適切に検索できません。
Standard Analyzer を使用して日本語を検索した場合
POST _analyze { "analyzer": "standard", "text": "東京都に行く" }
日本語には単語の間にスペースがないため、1文字ずつトークンナイズされます。
"tokens" : [ { "token" : "東", "start_offset" : 0, "end_offset" : 1, "type" : "", "position" : 0 }, { "token" : "京", "start_offset" : 1, "end_offset" : 2, "type" : " ", "position" : 1 }, { "token" : "都", "start_offset" : 2, "end_offset" : 3, "type" : " ", "position" : 2 }, { "token" : "に", "start_offset" : 3, "end_offset" : 4, "type" : " ", "position" : 3 }, { "token" : "行", "start_offset" : 4, "end_offset" : 5, "type" : " ", "position" : 4 }, { "token" : "く", "start_offset" : 5, "end_offset" : 6, "type" : " ", "position" : 5 }
1文字ずつトークンに分割することの何が問題かというと、1文字でも同じ文字が含まれると検索にヒットします。
例えば、「か"に"」は、「東京"に"行く」というドキュメントにヒットします。
PUT standard/_doc/1 { "text":"東京都に行く" }
GET standard/_search { "query": { "match": { "text": "かに" } } }
"hits" : [ { "_index" : "standard", "_type" : "_doc", "_id" : "1", "_score" : 0.18232156, "_source" : { "analyzer" : "standard", "text" : "東京都に行く"
そのため、日本語を検索する場合は、kuromoji Analyzer を使用します。
なお、kuromoji Analyzer は以下の要素から構成されます。
Analyzer | kuromoji Analyzer の構成要素 |
---|---|
Char Filter | CJKWidthCharFilter (Apache Lucene) |
Tokenizer | kuromoji_tokenizer |
Token Filter | kuromoji_baseform token filter kuromoji_part_of_speech token filterja_stop token filterkuromoji_stemmer token filterlowercase token filter |
kuromoji Analysis Plugin をインストール
kuromoji Analyzer を利用するためには、Elasticsearch に kuromoji Analysis Plugin をインストールする必要があります。
docker を利用しない方法
FROM docker.elastic.co/elasticsearch/elasticsearch:7.12.1 RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji
version: '3' services: elasticsearch: build: context: . dockerfile: Dockerfile container_name: elasticsearch environment: - discovery.type=single-node ports: - 9200:9200 kibana: image: kibana:7.12.1 ports: - "5601:5601" environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
※既に Elasticsearch, kibana コンテナを起動してる場合は、docker-compose down を実行してください。
kuromoji Analyzer の使い方
まずは、インデックス (demo_analyzer) に kuromoji Analyzer を設定します。
PUT demo_analyzer { "mappings": { "properties": { "text":{ "type": "text", "analyzer": "kuromoji" } } } }
kuromoji Analyzer のトークナイズ結果
トークナイズの結果を見ると、日本語らしくトークナイズされています。
POST _analyze { "analyzer": "kuromoji", "text": "東京都に行く" }
"tokens" : [ { "token" : "東京", "start_offset" : 0, "end_offset" : 2, "type" : "word", "position" : 0 }, { "token" : "都", "start_offset" : 2, "end_offset" : 3, "type" : "word", "position" : 1 }, { "token" : "行く", "start_offset" : 4, "end_offset" : 6, "type" : "word", "position" : 3 }
トークナイズ結果から、「京都」の検索ノイズとして「東京都」を回避できます。
kuromoji Analyzer で検索
次に demo_analyzer インデックスでドキュメントを作成し、日本語検索を行います。
PUT demo_analyzer/_doc/1 { "text":"東京都に行く" }
GET demo_analyzer/_search { "query": { "match": { "text": "東京" } } }
"hits" : [ { "_index" : "demo_analyzer", "_type" : "_doc", "_id" : "1", "_score" : 0.2876821, "_source" : { "text" : "東京都に行く" } }
無事に日本語で検索ができるようになりました。
関連記事
Elasticsearch に関する記事の続きは以下です。
- 【Elasticsearch 入門1】Elasticsearch とは (概要/できること/検索方法)
- 【Elasticsearch 入門2】マッピング管理とテンプレート
- 【Elasticsearch 入門3】Analyzer の設定 (日本語検索、トークナイズ) ←イマココ
- 【Elasticsearch 入門4】集計・分類 (Aggregations)
- 【Elasticsearch 入門5】Dynamic index settings の変更