PHP 中使用 ElasticSearch 的最佳實踐(一)
PHP 中使用 ElasticSearch 的最佳實踐
引言
PHP 開發者其實使用到 ES 的情況並不多,因為開發的大多數專案可能都沒有快速模糊搜尋的需求。
即使有這樣的需求,用 MySQL 的 like 查詢,就基本可以搞定需求了。
也就沒有必要殺雞用宰牛刀,使用 ES 了。
正是在這種情況下,導致很多的 PHP 開發者都沒有接觸過 ES。
即使有一些對 ES 有興趣的,也因為 ES 中文文件的缺乏,而放棄了。
因此,接下來的這篇文章就類比 MySQL 來使用 ES,讓大多數的 PHP 開發者能使用起 ES 來。
注:ElasticSearch 在文中簡稱 ES。
實現思路
我先簡單的描述一下需求:
實現一個商品的搜尋功能,只要含有搜尋關鍵字詞的就匹配,並且按照發布時間和價格倒序。
我這裡已經安裝好 MySQL 和 ES 了。如果沒有安裝的同學,可以先自行安裝。
先在 MySQL 中建立一張資料表 product
,建表語句如下:
CREATE TABLE `product` ( `product_id` int(11) UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '商品 ID', `name` varchar(64) NOT NULL DEFAULT '' COMMENT '商品名稱', `sku` varchar(32) NOT NULL DEFAULT '' COMMENT '商品 SKU', `price` decimal(4, 2) NOT NULL DEFAULT 0 COMMENT '商品價格', `sales` int(11) NOT NULL DEFAULT 0 COMMENT '商品銷量', `date_added` datetime COMMENT '建立時間', `date_modified` datetime COMMENT '修改時間' ) ENGINE = InnoDB CHARACTER SET = utf8mb4;
然後對應在 ES 中建立索引 product
// 建立索引並定義屬性 PUT http://127.0.0.1/product { "settings": { "number_of_shards": 1, "number_of_replicas": 1 }, "mappings": { "properties": { "product_id": { "type": "integer" }, "name" : { "type": "text" }, "sku": { "type": "text" }, "price": { "type": "double" }, "sales": { "type": "integer" }, "date_added": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || epoch_millis" }, "date_modified": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || epoch_millis" } } } }
建立好索引之後,我們就從 MySQL 將資料同步到 ES,同步的方案有如下三種:
1、可以直接在儲存入 MySQL 之後,就直接寫入 ES。
2、通過 Logstash 定時,從 MySQL 資料庫中拉取資料同步到 ES。
3、可以通過第三方中介軟體(例如:canal、go-mysql-elasticsearch),拉取 MySQL 的 binlog 日誌,之後中介軟體解析日誌將資料同步到 ES。
建立好索引和新增資料之後,在業務的發展過程中,可能會增加欄位。
這裡增加一個 description
欄位。
現在 MySQL 中增加欄位到 product
資料表。
alter table `product` add column description varchar(255) default "" comment "商品描述";
然後向 ES 中的 product
索引,增加屬性欄位。
// 增加對映欄位
// http://127.0.0.1:9200/product/_mapping
{
"properties": {
"description": {
"type": "text"
}
}
}
業務發展到中後時期的時候,可能發現欄位越來越多了,這個時候想要刪除一些欄位。
但是,在 ES 中的 Mapping 中是不能直接刪除欄位的,只能重新建立。
很多情況,我們還是不建議去刪除欄位,因為這會增加很多不必要的成本以及帶來的風險。
如果,為了節省儲存空間,Boss 一定要刪除欄位。那就按照下面的方法,也是可以實現的。
1、建立一個新的索引
2、建立新的對映關係 mapping
3、將原索引的資料到入到新索引
4、新索引建立原索引一致的別名
5、刪除原索引
下一篇文章,我將會介紹如何在 laravel 框架中使用 ES。