1. 程式人生 > >ElasticSearch學習(一)------建立索引庫,設定索引規則

ElasticSearch學習(一)------建立索引庫,設定索引規則

一、建立索引庫,並且設定預設分詞器為 IK

curl -XPUT http://localhost:9200/myindex -d '
{
    "settings" : {
        "index" : {
            "max_result_window" : 100000000
        },
        "analysis": {
            "analyzer": {
                "default": {
                    "type": "ik_max_word"
                }
            }
        }
    }
}
'

max_result_window 這個屬性指定了查詢數量限制,ES 預設限制了分頁查詢 start + limit <= 10000。

 

如果已經建立了索引庫,但是索引庫中還沒有內容的時候,需要更換分詞器,那麼需要先關閉索引庫,設定新的分詞器,在開啟索引庫。(索引庫中已經有內容的話,建議還是刪掉索引庫完全重建好了,舊索引分詞不符合預期也沒有留著的必要)

關閉索引庫:

curl -XPOST http://localhost:9200/myindex/_close -d '
{}
'

重新設定分詞器:

curl -XPUT http://localhost:9200/myindex -d '
{
    "settings" : {
        "index" : {
            "max_result_window" : 100000000
        },
        "analysis": {
            "analyzer": {
                "default": {
                    "type": "ik_max_word"
                }
            }
        }
    }
}
'

開啟索引庫:

curl -XPOST http://localhost:9200/myindex/_open -d '
{}
'

自定義分詞方式:

首先大概解釋幾個概念:

Analyzers:語法分析器,ES 包含很多內建的分析器,比如 standard, simple, whitespace 等等。

Tokenizer:分詞器,將指定文字分割為一個一個單詞。

Character Filter:當一串文字被傳遞到 Tokenizer 之前,可以用 Character Filter 過濾一遍,處理其中的字元,比如將指定的字元替換成別的字元。

Filter:經過 Tokenizer 分詞結束的單詞,可以用 filter 進行處理,比如將其轉換成小寫字母之類的。

接下來舉個例子,比如我輸入的文字為:“張三吃飯#李四洗澡”,我希望僅僅按照 # 分詞,也就是我最後得到的結果是 “張三吃飯”,“李四洗澡” 兩個詞語,並且 “張三吃飯”不會被分詞為 “張三”、“吃飯”兩個詞。

curl -XPUT http://localhost:9200/myindex -d '
{
    "settings": {
        "index": {
            "number_of_shards": 5,
            "number_of_replicas": 1,
            "max_result_window" : 100000000
        },
        "analysis": {
            "analyzer": {
                "default": {
                    "type": "ik_smart"
                },
                "my_analyzer": {
                    "type": "custom",
                    "tokenizer": "my_tokenizer"
                }
            },
            "tokenizer": {
                "my_tokenizer": {
                    "type": "pattern",
                    "pattern": "#"
                }
            }
        }
    },
    "mappings": {
        "mytype": {
            "properties": {
                "title": {
                    "type": "text",
                    "analyzer": "my_analyzer"
                }
            }
        }
    }
}
'

然後我將 “張三吃飯#李四洗澡”這串文字傳遞到 myindex/mytype 進行索引。

curl -XPOST http://localhost:9200/myindex/mytype/1 -d '
{
    "title": "張三吃飯#李四洗澡"
}
'

接著,查詢分詞結果:

curl -XGET http://localhost:9200/myindex/mytype/1/_termvectors?fields=title

得到結果:

{
    "_index": "myindex",
    "_type": "mytype",
    "_id": "1",
    "_version": 1,
    "found": true,
    "took": 46,
    "term_vectors": {
        "title": {
            "field_statistics": {
                "sum_doc_freq": 2,
                "doc_count": 1,
                "sum_ttf": 2
            },
            "terms": {
                "張三吃飯": {
                    "term_freq": 1,
                    "tokens": [
                        {
                            "position": 0,
                            "start_offset": 0,
                            "end_offset": 4
                        }
                    ]
                },
                "李四洗澡": {
                    "term_freq": 1,
                    "tokens": [
                        {
                            "position": 1,
                            "start_offset": 5,
                            "end_offset": 9
                        }
                    ]
                }
            }
        }
    }
}

可以看到分詞結果符合預期。

 

二、設定索引規則(mapping)

預設情況下,即使沒有事先設定 mapping,ES也會根據提交的 json 資料自動建立 mapping 規則,但是自動建立的 mapping 比較簡單,只會將欄位設定為 long 和 text 兩種型別。

手動建立 mapping 規則方法如下:

curl -XPOST http://localhost:9200/myindex/mytype/_mappings -d '
{
    "properties": {
        "id": {
            "type": "integer"
        },
        "title": {
            "type": "text"
        },
        "content": {
            "type": "text"
        }
    }
}
'

 

對於 String 欄位,可以設定型別為 text 或者 keyword。text型別的資料會被分詞處理,而 keyword 型別的資料不會被分詞處理。因此想根據某個欄位精確查詢的話,可以將其設定為 keyword 型別(版本5.0之後)。

如果一個索引庫已經存在索引文件,這時想要更改索引的mapping的話,最好刪除當前索引庫,重新建立索引庫,設定 mapping 之後,將資料重新新增到索引庫中。

mapping 的缺陷:

5.0 版本之後,在同一個索引庫中,相同名字的欄位 mapping type 只有一個(7.0 準備移除 mapping type 的概念),也就是說比如學生資訊有name欄位,學生成績資訊也有name欄位,這兩個name欄位在 Lucene 中是用一個欄位來儲存的。那麼意味著在每個索引庫中,每個被索引的欄位名必須不重複。

ES 早期的概念中,將 index 類比於資料庫,將type類比於表,這對於索引是不合理的,在最新的文件中他們也承認了這個問題,每個 table 中的欄位名即使重複,也不會對於其他表造成影響,而在 Lucene 中並不是這樣,相同的欄位應該就是隻有一份索引。

以上問題就意味著,如果你想要對兩個有關聯的 table (比如外來鍵)單獨做到一個索引庫的兩個type中是不會成功的,因為有相同的欄位名。如果你確實想對這兩個table中的資料做索引,那麼最好是建立一個獨立的資料物件,包含了這兩個表中所有欄位(去掉重複部分),然後將整個物件做索引。

三、重建 setting 或者  mapping 無縫遷移生產環境資料

        程式開發設計時總會有缺陷,當你的索引庫 setting 或者 mapping 需要重建時,最簡單粗暴的辦法當然是刪除索引庫,按照新規則建立索引庫,然後重新建立索引,但是這種暴力方式會導致你的服務一段時間內不可用,資料量越大,影響時間越長。

        其實我們可以通過給索引庫建立別名的方式,來解決這個問題,基本的思路就是,給你的舊 index 取一個別名為 index-alias,然後程式碼中使用 index-alias去訪問 index, 然後按照新規則建立一個 index2, 將 index 中的資料完全重新索引到 index2 中,然後將 index-alias 這個別名,跟 index2 繫結起來,這樣就做到了重建索引庫之後無縫切換,整個切換過程中服務依舊可以使用,只是會有部分搜尋結果不正常,但是總比完全停止要好。

1. 給現有索引庫建立別名

curl -X POST http://localhost:9200/_aliases -d '
{
    "actions": [
        { "add" : { "index" : "index", "alias" : "index-alias" } }
    ]
}
'

2. 建立新的 index2

curl -X PUT http://localhost:9200/index2 -d '
{
    "settings": {
        "index": {
            "number_of_shards": 5,
            "number_of_replicas": 1,
            "max_result_window" : 100000000
        },
        "analysis": {
            "analyzer": {
                "default": {
                    "type": "ik_max_word"
                }
            }
        }
    },
    "mappings": {
        "user": {
            "properties": {
                "name": {
                    "type": "keyword"
                }
            }
        }
    }
}
'

3. 將 index 中的資料完全重建索引到 index2 中

curl -X POST http://localhost:9200/_reindex -d '
{
    "source": {
        "index": "index"
    },
    "dest": {
        "index": "index2"
    }
}
'

4. 更換別名

curl -X POST http://localhost:9200/_aliases -d '
{
    "actions": [
    	{ "remove" : { "index" : "index", "alias" : "index-alias" } },
        { "add" : { "index" : "index2", "alias" : "index-alias" } }
    ]
}
'

5. 刪除舊索引庫

curl -X DELETE http://localhost:9200/index

至此,索引庫重建完畢。

 

如果僅僅是 mapping 新增欄位的話,可以簡單一點(因為是新增,此時 ES 裡面應該沒有需要新增的欄位的資料)

curl -H "Content-Type: application/json" -X POST http://localhost:9200/index-alias/type1/_mapping -d '
{
	"properties": {
		"newPropertity": {
			"type": "nested"
		}
	}
}
'