ES-MySQL-PHP的使用

程式設計師的貓發表於2020-08-31

ES簡介

一個高擴充套件、開源的全文檢索和分析引擎,它可以準實時地快速儲存、搜尋、分析海量的資料。
全文檢索是指計算機索引程式透過掃描文章中的每一個詞,對每一個詞建立一個索引,指明該詞在文章中出現的次數和位置,當使用者查詢時,檢索程式就根據事先建立的索引進行查詢,並將查詢的結果反饋給使用者的檢索方式。這個過程類似於透過字典中的檢索字表查字的過程。全文搜尋搜尋引擎資料庫中的資料

ES 為什麼比 mysql 快

Mysql 只有 term dictionary 這一層,是以 b-tree 排序的方式儲存在磁碟上的。檢索一個 term 需要若干次的 random access 的磁碟操作。而 Lucene 在 term dictionary 的基礎上新增了 term index 來加速檢索,term index 以樹的形式快取在記憶體中。從 term index 查到對應的 term dictionary 的 block 位置之後,再去磁碟上找 term,大大減少了磁碟的 random access 次數。另外:term index 在記憶體中是以 FST(finite state transducers)的形式儲存的,其特點是非常節省記憶體。Term dictionary 在磁碟上是以分 block 的方式儲存的,一個 block 內部利用公共字首壓縮,比如都是 Ab 開頭的單詞就可以把 Ab 省去。這樣 term dictionary 可以比 b-tree 更節約磁碟空間。

同步資料庫

我們採取 MySQL 的資料儲存,利用 MySQL 的事務特性維護資料一致性,使用 ElasticSearch 進行資料彙集和查詢,此時 es 與資料庫的同步方案就尤為重要。

流程

首先新增商品入資料庫,新增商品成功後,商品入 ES,若入 ES 失敗,將失敗的商品 ID 放入 redis 的快取佇列,且失敗的商品 ID 入 log 檔案(若出現 redis 掛掉,可從日誌中取異常商品 ID 然後再入 ES),task 任務每秒重新整理一下 redis 快取佇列,若是從快取佇列中取到商品 ID,則根據商品 ID 從資料庫中獲取商品資料然後入 ES。

使用

logstash-input-jdbc 外掛同步資料庫,安裝,配置:建立一個 .conf 檔案,配置了要同步的資料庫和.sql 用於執行的 sql 語句,最後把一個 jdbc 驅動放到這個資料夾下,用來連線 mysql 資料庫

可能遇到的問題

elasticsearch 資料重複以及增量同步

在預設配置下,tracking_column 這個值是 @timestamp,存在 elasticsearch 就是_id 值,是 logstash 存入 elasticsearch 的時間,這個值的主要作用類似 mysql 的主鍵,是唯一的,但是我們的時間戳其實是一直在變的,所以我們每次使用 select 語句查詢的資料都會存入 elasticsearch 中,導致資料重複。

解決方法

在要查詢的表中,找主鍵或者自增值的欄位,將它設定為_id 的值,因為_id 值是唯一的,所以,當有重複的_id 的時候,資料就不會重複

資料同步頻繁,影響 mysql 資料庫效能

我們寫入 jdbc.sql 檔案的 mysql 語句是寫死的,所以每次查詢的資料庫有很多是已經不需要去查詢的,尤其是每次 select * from table; 的時候,對 mysql 資料庫造成了非常大的壓力

解決:

(1) 根據業務需求,可以適當修改定時同步時間,我這裡對實時性相對要求較高,因此設定了 10 分鐘 schedule => “*/10 * * * *”
(2) 設定 mysql 查詢範圍,防止大量的查詢拖死資料庫,在 sql 語句這裡設定 select * from WHERE autoid > :sql_last_value;

elasticsearch 儲存容量不斷上升

elasticsearch 為了資料安全,接收到資料後,先將資料寫入記憶體和 translog,然後再建立索引寫入到磁碟,這樣即使突然斷電,重啟後,還可以透過 translog 恢復,不過這裡由於我們每次查詢都有很多重複的資料,而這些重複的資料又沒有寫入到 elasticsearch 的索引中,所以就囤積了下來,導致 elasticsearch 容量就不斷上升

解決:

查詢官網說會定期 refresh,會自動清理掉老的日誌,因此可不做處理

增量同步和 mysql 範圍查詢導致 mysql 資料庫有修改時無法同步到以前的資料。

解決了 mysql 每次都小範圍查詢,解決了資料庫壓力的問題,不過卻導致無法同步老資料的修改問題

解決:

可根據業務狀態來做,如果你資料庫是修改頻繁型別,那隻能做全量更新了,但是高頻率大範圍掃描資料庫來做的索引還不如不做索引了 (因為建立索引也是有成本的),我們做索引主要是針對一些資料量大,不常修改,很消耗資料庫效能的情況。我這裡是資料修改較少,而且修改也一般是近期資料,因為同步時,我在 mysql 範圍上面稍微調整一下

php 使用 ES

php composer 安裝 composer require elasticsearch/elasticsearch
引入 es 檔案 autoload.php 檔案,設定 IP 地址
建立 index,index 對應關係型資料(以下簡稱 MySQL)裡面的資料庫,而不是對應 MySQL 裡面的索引
有了資料庫還不行,還需要建立表,ES 也是一樣的,ES 中的 type 對應 MySQL 裡面的表。type 不是單獨定義的,而是和欄位一起定義,欄位定義在 body 中;當然可以在 body 欄位中也能使用 ik 分詞;
使用 EsClient->search () 實現搜尋;
同義詞和近義詞的使用

配置分詞器:配置 IK

下載 es 的 ik 版本包
在 es 目錄下的 plugins 在建立 ik 目錄,把下載 ik 的 zip 包所有檔案解壓進去。
進去 es 的 config 目錄,編輯 elasticsearch.yml,在空白地方加上 index.analysis.analyzer.default.type : “ik” 即可。
拼音分詞器配置:使用已經編譯好的:elasticsearch-analysis-pinyin-1.3.0
在 elasticsearch 的 plugins 目錄下,新建 analysis-pinyin 資料夾,解壓壓縮包,將裡面的 jar 包放到 analysis-pinyin 資料夾。
在 elasticsearch.yml 裡面配置拼音分詞器的過濾器

同義詞分詞器配置

在 elasticsearch.yml 裡面配置好同義詞分詞器的過濾器
配置同義詞詞庫,在 elasticsearch 的 config 目錄下新建 sysnonym.txt。
配置 ik+pinying + 同義詞的分詞器,主要有分詞器的名稱,型別,分割詞元的元件,對分割的次元做處理:這裡使用的是拼音和同義詞

ES 關鍵字高亮顯示

ES 透過在查詢的時候可以在查詢之後的欄位資料加上 html 標籤欄位,使文件在在 web 介面上顯示的時候是由顏色或者字型格式的,是在 highlight 修飾高亮欄位, 這個部分包含了 name 屬性匹配的文字片段,並以 HTML 標籤 封裝

ES 查詢分頁

Elasticsearch 中資料都儲存在分片中,當執行搜尋時每個分片獨立搜尋後,資料再經過整合返回。

一般查詢流程為

1) 客戶端請求發給某個節點
2) 節點轉發給個個分片,查詢每個分片上的前 10 條
3) 結果返回給節點,整合資料,提取前 10 條
4) 返回給請求客戶端
當我們查詢第 10 條到第 20 條的資料時,有兩種方式,包括深度分頁 (from-size) 和快照分頁 (scroll);
深度分頁 (from-size)

from 定義了目標資料的偏移值,size 定義當前返回的事件數目。預設 from 為 0,size 為 10,也就是說所有的查詢預設僅僅返回前 10 條資料。查詢前 20 條資料,然後截斷前 10 條,只返回 10-20 的資料。浪費了前 10 條的查詢。越往後的分頁,執行的效率越低。分頁的偏移值越大,執行分頁查詢時間就會越長

快照分頁 (scroll)

相對於 from 和 size 的分頁來說,使用 scroll 可以模擬一個傳統資料的遊標,記錄當前讀取的文件資訊位置。這個分頁的用法,不是為了實時查詢資料,而是為了一次性查詢大量的資料(甚至是全部的資料)。因為這個 scroll 相當於維護了一份當前索引段的快照資訊,這個快照資訊是你執行這個 scroll 查詢時的快照。在這個查詢後的任何新索引進來的資料,都不會在這個快照中查詢到。但是它相對於 from 和 size,不是查詢所有資料然後剔除不要的部分,而是記錄一個讀取的位置,保證下一次快速繼續讀取。
流程:

  • 呼叫: index/type/_search?pretty&scroll=2m,返回一個 scroll 值
  • 直接用 scroll_id 進行查詢。
  • 清除 scroll,我們在設定開啟 scroll 時,設定了一個 scroll 的存活時間,但是如果能夠在使用完順手關閉,可以提早釋放資源,降低 ES 的負擔
本作品採用《CC 協議》,轉載必須註明作者和本文連結
你還差得遠吶!