使用ElasticSearch服務(wù)從MySQL同步數(shù)據(jù)實現(xiàn)搜索即時提示與全文搜索功能
最近用了幾天時間為公司項目集成了全文搜索引擎,項目初步目標(biāo)是用于搜索框的即時提示。數(shù)據(jù)需要從MySQL中同步過來,因為數(shù)據(jù)不小,因此需要考慮初次同步后進(jìn)行持續(xù)的增量同步。這里用到的開源服務(wù)就是ElasticSearch。
ElasticSearch是一個非常好用的開源全文搜索引擎服務(wù),同事推薦之前我并沒有了解過,但是看到亞馬遜專門提供該服務(wù)的實例,沒有多了解之前便猜想應(yīng)該是和Redis一樣名聲在外的產(chǎn)品,估計也是經(jīng)得起考驗可以用在生產(chǎn)環(huán)境中了。上網(wǎng)了解一番之后發(fā)現(xiàn)果然如此:
廢話不多說,按照慣例記錄一下我的搭建過程。
安裝ElasticSearch
安裝有幾種方式,我個人還是比較喜歡CentOS的yum從源安裝。
CentOS的Yum方式安裝
首先進(jìn)入/etc/yum.repos.d目錄,建立一個名為elasticsearch.repo的源,內(nèi)容填寫如下:
[elasticsearch-6.x]
name=Elasticsearch?repository?for?6.x?packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
這里Elastic目前最新版本為6.2,但與之對應(yīng)的Elasticsearch-PHP需要PHP版本為7.0以上。由于公司的PHP版本是5.x,因此只有退而求其次,選擇了稍微老一點的5.6.9版本,5.x版本的安裝,只需要在這一步將上面源文件內(nèi)容中的所有6.x換成5.x即可。
接下來執(zhí)行
yum?install?elasticsearch
完成安裝后,默認(rèn)服務(wù)是僅僅本地可以訪問,如果需要從另一臺內(nèi)網(wǎng)服務(wù)器訪問,還需要打開監(jiān)聽范圍。進(jìn)入安裝目錄/usr/share/elasticsearch,編輯elasticsearch.yml文件,修改以下部分:
network.host:?0.0.0.0
path.data:?/var/lib/elasticsearch
path.logs:?/var/log/elasticsearch
http.host:?0.0.0.0
transport.host:?127.0.0.1
其中network.host是開啟外部網(wǎng)絡(luò)訪問,而path.data和path.logs由于默認(rèn)路徑?jīng)]有設(shè)置正確,這里需要手工設(shè)置一下。路徑設(shè)置完成后需要確認(rèn)一下這兩個目錄是否存在,如果目錄內(nèi)有上一次安裝的殘余內(nèi)容,需要備份后清空,否則會引發(fā)一些問題。更多視頻教程微信搜索:【碼農(nóng)編程進(jìn)階筆記】
接著重啟服務(wù):
service?elasticsearch?restart
安裝完成測試
重啟完成后,在瀏覽器中輸入
http://127.0.0.1:9200/?pretty如果能看到對應(yīng)的信息,表示安裝成功
安裝LogStash
接著安裝LogStash服務(wù),這個服務(wù)用于匯總各類log日志信息到一個地方統(tǒng)一管理,而這里我們用到這個服務(wù),是因為需要用它來實現(xiàn)數(shù)據(jù)從MySQL到Elastic的同步。
YUM方式安裝LogStash
這同樣是Elastic家的產(chǎn)品,因此包含在前面設(shè)置的源中,現(xiàn)在安裝只需要執(zhí)行:
yum?install?logstash
這樣就完成了安裝。接下來別急,還需要安裝一個插件。
安裝logstash-input-jdbc插件
首先進(jìn)入/usr/share/logstash/bin目錄,執(zhí)行:
./logstash-plugin?install?logstash-input-jdbc插件安裝完成后,logstash的安裝目前算是完成了。還有很多插件可以實現(xiàn)各種豐富的功能,而這里就咱不多說了。
配置同步MySQL數(shù)據(jù)到Elastic
接著就是比較重點的地方,配置數(shù)據(jù)從MySQL庫同步到Elastic。首先在任意目錄建立同步配置文件,我這里的同步腳本并不多,因此就直接把他們放在logstash的執(zhí)行目錄里:
cd?/usr/share/logstash/bin
mkdir?ktsee
cd?ktsee
然后新建兩個文件jdbc.conf和jdbc.sql,其中jdbc.conf是同步配置文件,jdbc.sql同步的mysql腳本。首先編輯jdbc.conf,填入內(nèi)容:
input?{
??stdin?{
??}
??jdbc?{
??#?mysql?jdbc?connection?string?to?our?backup?databse??后面的ktsee對應(yīng)mysql中的test數(shù)據(jù)庫
??jdbc_connection_string?=>?"jdbc:mysql://192.168.1.1:3306/ktsee"
??#?the?user?we?wish?to?excute?our?statement?as
??jdbc_user?=>?"root"
??jdbc_password?=>?"password"
??#?the?path?to?our?downloaded?jdbc?driver?這里需要設(shè)置正確的mysql-connector-java-5.1.38.jar路徑,找不到可以從網(wǎng)上下載后放在配置路徑中
??jdbc_driver_library?=>?"/elasticsearch-jdbc-2.3.2.0/lib/mysql-connector-java-5.1.38.jar"
??#?the?name?of?the?driver?class?for?mysql
??jdbc_driver_class?=>?"com.mysql.jdbc.Driver"
??jdbc_paging_enabled?=>?"true"
??jdbc_page_size?=>?"50000"
#?以下對應(yīng)著要執(zhí)行的sql的絕對路徑;更多視頻教程微信搜索:【碼農(nóng)編程進(jìn)階筆記】
??statement_filepath?=>?"/usr/local/logstash/bin/logstash_jdbc_test/jdbc.sql"
#?定時字段?各字段含義(由左至右)分、時、天、月、年,全部為*默認(rèn)含義為每分鐘都更新
??schedule?=>?"*?*?*?*?*"
#?設(shè)定ES索引類型
??type?=>?"ktsee_type"
??}
}
filter?{
??json?{
??source?=>?"message"
??remove_field?=>?["message"]
??}
}
output?{
??elasticsearch?{
#ESIP地址與端口
??hosts?=>?"192.168.1.1:9200"
#ES索引名稱(自己定義的)
??index?=>?"ktsee_index"
#自增ID編號
??document_id?=>?"%{id}"
??}
??stdout?{
#以JSON格式輸出
??codec?=>?json_lines
??}
}
這里需要注意的地方,在上面配置文件中有相應(yīng)的注釋。
使用Elasticsearch-PHP庫集成到項目中
這里選擇使用Elasticsearch的官方PHP庫Elasticsearch-PHP,如果項目使用composer進(jìn)行包管理,那么很簡單,直接安裝對應(yīng)的版本即可,composer會自動下載其他的依賴庫。在項目中添加代碼:
1$client?=?\Elasticsearch\ClientBuilder::create()
2????->setHosts(['192.168.1.1:9200'])
3????->allowBadJSONSerialization()
4????->build();
5$params?=?[
6????'index'?=>?'ktsee_index',
7????'_source'?=>?[
8????????"id",
9????????"product_name",
10????????"product_type"
11????],
12????'body'?=>?[
13????????'query'?=>?[
14????????????'match_phrase_prefix'?=>?[
15????????????????'product_name'?=>?[
16????????????????????"query"?=>?$post['keyword'],
17????????????????????"slop"?=>?10
18????????????????]
19????????????],
20????????]
21????]
22];
23$response?=?$client->search($params);
這樣就實現(xiàn)了簡單的根據(jù)關(guān)鍵詞搜索調(diào)用ElasticSearch。
實現(xiàn)搜索即時提示代碼
HTML部分:
1<form?method="get"?action="/search"?id="header_search">
2????<input?type="text"?id="keyword"?name="keyword"?value=""?autocomplete="off"?/>
3????<input?type="submit"?value=""?/>
4form>
5<ul?id="header_search_suggest">ul>這里值得注意的是,搜索框input控件加上autocomplete="off"關(guān)閉原生下拉提示框,避免和我們即將要做的智能提示沖突。
CSS部分:
#header_search_suggest{
????position:?absolute;
????width:?calc(100%?-?10px);
????left:?4px;
????border:?solid?1px?#ccc;
????background-color:?white;
????text-align:?left;
????z-index:?101;
????display:?none;
}
#header_search_suggest?li{
????font-size:?14px;
????border-bottom:?1px?solid?#eeeeee;
}
#header_search_suggest?li?a{
????padding:0.5em?1em;
????color:#333333;
????display:?block;
????text-decoration:?none;
}
#header_search_suggest?li?a:hover{
????background-color:?#EDF0F2;
????color:#2F7EC4;
}
#header_search_suggest?li?a?em{
????font-style:?italic;
????color:#999;
????font-size:0.8em;
}JS部分:
1var?xhr?=?null;
2$('#keyword').bind('input?propertychange',?function?()?{
3????if?(xhr)?{
4????????xhr.abort();//如果存在ajax的請求,就放棄請求,更多視頻教程微信搜索:【碼農(nóng)編程進(jìn)階筆記】
5????}
6????var?inputText?=?$.trim(this.value);
7????if?(inputText?!=?"")?{?//檢測鍵盤輸入的內(nèi)容是否為空,為空就不發(fā)出請求
8????????xhr?=?$.ajax({
9????????????type:?'POST',
10????????????url:?'/search/suggest',
11????????????cache:?false,//不從瀏覽器緩存中加載請求信息
12????????????//?data:?"keyword="?+?inputText,
13????????????data:?{keyword:?inputText},
14????????????dataType:?'json',
15????????????success:?function?(json)?{
16????????????????//console.log(json);
17????????????????if?(json.count?!=?0)?{
18????????????????????//檢測返回的結(jié)果是否為空
19????????????????????var?lists?=?"";
20????????????????????$.each(json.data,?function?(index,?obj)?{
21????????????????????????//處理高亮關(guān)鍵詞
22????????????????????????var?searchContent?=?obj.product_name;
23????????????????????????var?suggestItem?=?'';
24????????????????????????if?(searchContent.toLowerCase().indexOf(inputText.toLowerCase())?>?-1)?{
25????????????????????????????var?searchRegExp?=?new?RegExp('('?+?inputText?+?')',?"gi");
26????????????????????????????suggestItem?=?searchContent.replace(searchRegExp,?("$1"));
27????????????????????????}
28????????????????????????suggestItem?=?suggestItem?+?"?-?"?+?obj.product_type?+?"";
29????????????????????????//遍歷出每一條返回的數(shù)據(jù)
30????????????????????????lists?+=?"?+?obj.product_type)?+?"'>"?+?suggestItem?+?" ";
31????????????????????});
32????????????????????$("#header_search_suggest").html(lists).show();//將搜索到的結(jié)果展示出來
33????????????????}?else?{
34????????????????????$("#header_search_suggest").hide();
35????????????????}
36????????????????//記錄搜索歷史記錄
37????????????????$.post('/search/savesearchlog',{keyword:?inputText,count:?json.count});
38????????????}
39????????});
40????}?else?{
41????????$("#header_search_suggest").hide();//沒有查詢結(jié)果就隱藏搜索框
42????}
43}).blur(function?()?{
44????setTimeout('$("#header_search_suggest").hide()',500);//輸入框失去焦點的時候就隱藏搜索框,為了防止隱藏過快無法點擊,設(shè)置延遲0.5秒隱藏
45});演示效果
如圖:

最后
你的點贊關(guān)注是對我最大的支持,求一鍵三連:分享朋友圈、點贊、在看
公眾號后臺回復(fù)666,可以獲得免費(fèi)電子書籍

