
まずは、結論としてよく利用するコマンドを書いておきます。
PUT demo_analyzer
{
"mappings": {
"properties": {
"text":{
"type": "text",
"analyzer": "kuromoji",
"search_analyzer": "kuromoji"
}
}
}
}
GET _analyze
{
"analyzer": "kuromoji",
"text": "東京都は日本の首都です。"
}
GET /_analyze
{
"tokenizer" : {
"type": "ngram",
"min_gram":2
},
"text" : "quick"
}
| Elasticsearch & OpenSearch の使い方 | ||||
|---|---|---|---|---|
| 学習ロードマップ | |||||
|---|---|---|---|---|---|
Analyzer の構成要素と一覧
Analyzer は、以下の3つの要素によって構成されます。
| Analyzer の要素 | 説明 |
|---|---|
| Character Filter | ドキュメントの内容をフィルタリング、置換 |
| Tokenizer | ドキュメントの内容をトークン(単語)に分割 |
| Token filter | トークン (単語) のフィルタリング ・ストップワード ・シノニム ・ステミング |


Character Filter には、次の種類があります。
| Character Filter の種類 | 説明 | 例 |
|---|---|---|
| HTML strip | HTML タグを除去 | <p>タグを除去 <p>Elasticsearch</p> → Elasticsearch |
| Mapping | マッピングを作成 | アラビア数字をラテン数字にマッピング [٠١٢٣٤٥٦٧٨٩] → [0123456789] |
| Pattern replace | 正規表現で置換 | ハイフンをアンダースコアに置換 [123-456-789] → [123_456_789] |
Character Filter の使い方
HTML strip character filter で、HTML タグをフィルタリングしてみます。
GET /_analyze
{
"char_filter" : ["html_strip"],
"text" : "<p>Elasticsearch is simple</p>"
}
"token" : """Elasticsearch is simple""",
HTML strip character filter で、<p> タグが除去できました。

Tokenizer には、次の種類があります。
| Tokenizer の種類 | 説明 | 例 |
|---|---|---|
| ■単語指向分割 (形態素解析) kuromoji_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 ] |
この中でよく利用する、単語指向分割 (形態素解析) と N-gram 分割について解説します。
形態素と単語の違い
形態素はそれ以上分割できないが、単語は分割できる場合もある
「お金」(単語)は、
「お」(拘束)形態素と、「金」(自由)形態素に分解できます。
「お」は単語じゃないですが、「金」は単語です。
形態素解析には、主に次の2種類があります。
- 空白で分割
- 辞書/ラティスで分割
空白で分割
空白でドキュメント (文章) をトークン (単語) に分割する方法です。
Elasticsearch is simple --> [Elasticsearch], [is], [simple]
英語では実用的な方法ですが、日本語は空白で文章が区切られないので使いにくいです。
Elasticsearchはシンプルです --> [Elasticsearchはシンプルです]
そこで日本語の場合は「辞書/ラティス」を利用します。
辞書/ラティスで分割
辞書にある単語を使って、自然な日本語 (コストの低い経路) にドキュメントを分割する方法です。

以下の2つのコストの合計が最も低い経路 (最も自然な日本語) を選択します。
- 生起コスト:単語の出現しやすさ (例: 「アベック」より「カップル」の方がよく言う)
- 連接コスト:2つの単語の繋がりやすさ (動詞の後は格助詞は NG [例: ドアを開ける"を"])
なお、辞書に載ってない単語の検索漏れが発生する欠点があります。
- 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 の使い方
Whitespace 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
}

Token Filter には、次の種類があります。
| Token Filter の種類 | 説明 | 例 |
|---|---|---|
| Lower case Token Filter | トークンを小文字に変換 | [Elasticsearch] → [elasticsearch] |
| 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 の使い方
Stop token filter で、ストップワードの is をフィルタリングしてみます。
GET /_analyze
{
"tokenizer": "whitespace",
"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 | Character Filter, Tokenizer, Token Filter が事前に定義されている |
| Custom analyzer | Character Filter, Tokenizer, Token Filter を自分で定義する |
分析プラグインは事前に定義されているので built-in のように使えます。日本語検索の kuromoji analyzer は分析プラグインに相当
Analyzer はインデックス時と検索時で利用し、デフォルトは Standard Analyzer で分析します。

Standard Analyzer の構成は以下のとおりです。
| 構成要素 | Standard Analyzer の構成 |
|---|---|
| Character filter | なし |
| Tokenizer | Standard Tokenizer |
| Token filter | Lower Case Token Filter Stop Token Filter (disabled by default) |
Built-in analyzer の設定
インデックス (built-in) に、Built-in analyzer の Whitespace analyzer を設定してみます。
PUT built-in
{
"mappings": {
"properties": {
"str": {
"type": "text",
"analyzer": "whitespace",
"search_analyzer": "whitespace"
}
}
}
}
これで text フィールドのインデックス時と検索時に Built-in Analyzer が使用されます。
※analyzer = インデックス時, search_analyzer = 検索時
Built-in analyzer の分析結果
GET built-in/_analyze
{
"analyzer":"whitespace",
"text": "Elasticsearch is simple"
}
"tokens": [
{
"token": "elasticsearch",
"start_offset": 0,
"end_offset": 13,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "is",
"start_offset": 14,
"end_offset": 16,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "simple",
"start_offset": 17,
"end_offset": 23,
"type": "<ALPHANUM>",
"position": 2
}
Custom analyzer の設定
インデックスに次の Custom analyzer を設定してみます。
| Analyzer の要素 | 構成 | やりたいこと |
|---|---|---|
| Character Filter | HTML strip character filter | ドキュメントから <p> タグを除去 |
| Tokenizer | Whitespace tokenizer | ドキュメントを空白でトークン (単語) に分割 |
| Token filter | Stop token filter Lowercase token filter | トークンから "This", "is" を除去 大文字のトークンを小文字にする |
インデックス (custom) に、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": {
"str": {
"type": "text",
"analyzer": "my_custom_analyzer",
"search_analyzer": "my_custom_analyzer"
}
}
}
}
Custom analyzer の分析結果
GET 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
HTML タグは消え、"This", "is" は削除され、"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 の構成
kuromoji Analyzer は以下の要素で構成されます。
| 構成要素 | kuromoji Analyzer の要素 |
|---|---|
| Character 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",
"search_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 のインデックスと検索結果を確認
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" : "東京都に行く"
}
}
東京では無事ヒットしました。
次に「京都」で「東京都」が検索ノイズにならないことを確認します。
GET demo_analyzer/_search
{
"query": {
"match": {
"text": "京都"
}
}
}
"hits": []
無事に「京都」で「東京都」がヒットせず、日本語らしい検索ができています。
関連記事
| Elasticsearch & OpenSearch の使い方 | ||||
|---|---|---|---|---|
| 学習ロードマップ | |||||
|---|---|---|---|---|---|













![Elastic Stack実践ガイド[Elasticsearch/Kibana編] impress top gearシリーズ](https://m.media-amazon.com/images/I/51ieij7UhAL._SL160_.jpg)





























![[増補改訂]ビッグデータを支える技術 ——ラップトップ1台で学ぶデータ基盤のしくみ WEB+DB PRESS plus](https://m.media-amazon.com/images/I/51V-rBEb0PL._SL160_.jpg)
