Elasticsearch學習筆記
Why Elasticsearch?
由于需要提升項目的搜索質量,最近研究了一下Elasticsearch,一款非常優秀的分布式搜索程序。最開始的一些筆記放到github,這里只是歸納總結一下。
首先,為什么要使用Elasticsearch?最開始的時候,我們的項目僅僅使用MySQL進行簡單的搜索,然后一個不能索引的like語句,直接拉低MySQL的性能。后來,我們曾考慮過sphinx,并且sphinx也在之前的項目中成功實施過,但想想現在的數據量級,多臺MySQL,以及搜索服務本身HA,還有后續擴容的問題,我們覺得sphinx并不是一個最優的選擇。于是自然將目光放到了Elasticsearch上面。
根據官網自己的介紹,Elasticsearch是一個分布式搜索服務,提供Restful API,底層基于Lucene,采用多shard的方式保證數據安全,并且提供自動resharding的功能,加之github等大型的站點也采用 Elasticsearch作為其搜索服務,我們決定在項目中使用Elasticsearch。
對于Elasticsearch,如果要在項目中使用,需要解決如下問題:
- 索引,對于需要搜索的數據,如何建立合適的索引,還需要根據特定的語言使用不同的analyzer等。
- 搜索,Elasticsearch提供了非常強大的搜索功能,如何寫出高效的搜索語句?
- 數據源,我們所有的數據是存放到MySQL的,MySQL是唯一數據源,如何將MySQL的數據導入到Elasticsearch? </ol>
- Document:用來索引和搜索的主要數據源,包含一個或者多個Field,而這些Field則包含我們跟Lucene交互的數據。
- Field:Document的一個組成部分,有兩個部分組成,name和value。
- Term:不可分割的單詞,搜索最小單元。
- Token:一個Term呈現方式,包含這個Term的內容,在文檔中的起始位置,以及類型。 </ul>
- Elasticsearch Server 1.0 (document 1)
- Mastring Elasticsearch (document 2)
- Apache Solr 4 Cookbook (document 3) </ul>
- Index:Elasticsearch用來存儲數據的邏輯區域,它類似于關系型數據庫中的db概念。一個index可以在一個或者多個shard上面,同時一個shard也可能會有多個replicas。
- Document:Elasticsearch里面存儲的實體數據,類似于關系數據中一個table里面的一行數據。
document由多個field組成,不同的document里面同名的field一定具有相同的類型。document里面field可以重復出現,也就是一個field會有多個值,即multivalued。 - Document type:為了查詢需要,一個index可能會有多種document,也就是document type,但需要注意,不同document里面同名的field一定要是相同類型的。
- Mapping:存儲field的相關映射信息,不同document type會有不同的mapping。 </ul>
- Node: 一個server實例。
- Cluster:多個node組成cluster。
- Shard:數據分片,一個index可能會存在于多個shards,不同shards可能在不同nodes。
- Replica:shard的備份,有一個primary shard,其余的叫做replica shards。 </ul>
- binlog一定要變成row-based format格式,其實我們并不需要擔心這種格式的binlog占用太多的硬盤空間,MySQL 5.6之后GTID模式都推薦使用row-based format了,而且通常我們都會把控SQL語句質量,不允許一次性更改過多行數據的。
- 需要同步的table最好是innodb引擎,這樣mysqldump的時候才不會阻礙寫操作。
- 需要同步的table一定要有主鍵,好吧,如果一個table沒有主鍵,筆者真心會懷疑設計這個table的同學編程水平了。多列主鍵也是不推薦的,筆者現階段不打算支持。
- 一定別動態更改需要同步的table結構,Elasticsearch只能支持動態增加field,并不支持動態刪除和更改field。通常來說,如果涉及到alter table,很多時候已經證明前期設計的不合理以及對于未來擴展的預估不足了。 </ul>
對于1和2,因為我們的數據都是從MySQL生成,index的field是固定的,主要做的工作就是根據業務場景設計好對應的mapping以及search語句就可以了,當然實際不可能這么簡單,需要我們不斷的調優。
而對于3,則是需要一個工具將MySQL的數據導入Elasticsearch,因為我們對搜索實時性要求很高,所以需要將MySQL的增量數據實時導入,筆者唯一能想到的就是通過row based binlog來完成。而近段時間的工作,也就是實現一個MySQL增量同步到Elasticsearch的服務。
Lucene
Elasticsearch底層是基于Lucene的,Lucene是一款優秀的搜索lib,當然,筆者以前仍然沒有接觸使用過。:-)
Lucene關鍵概念:
Lucene使用Inverted index來存儲term在document中位置的映射關系。
譬如如下文檔:
使用inverted index存儲,一個簡單地映射關系:
Term | Count | Docuemnt | </tr> </tbody>|||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1.0 | 1 | <1> | </tr>|||||||||||||||||||
4 | 1 | <3> | </tr>|||||||||||||||||||
Apache | 1 | <3> | </tr>|||||||||||||||||||
Cookbook | 1 | <3> | </tr>|||||||||||||||||||
Elasticsearch | 2 | <1>.<2> | </tr>|||||||||||||||||||
Mastering | 1 | <2> | </tr>|||||||||||||||||||
Server | 1 | <1> | </tr>|||||||||||||||||||
Solr | 1 | <3> | </tr> </tbody> </table>