Recently spent a few days with integrated full-text search engine for the company's project, the initial goal of the project is the immediate prompt for the search box. Need to synchronize data coming from MySQL, since the data is not small, it is necessary to consider the initial ongoing incremental synchronization after synchronization. Here used open source service is ElasticSearch.
ElasticSearch is a very easy to use open source full-text search engine service, before a colleague recommended I did not understand before, but to see examples of Amazon specializes in providing the service, then guess not previously know more about Redis and should be the same as the reputation of the product, the estimated but also stand the test can be used in a production environment. After the discovery of the Internet to understand something is really the case:
Full-text search are among the most common needs, open source Elasticsearch is now the preferred full-text search engine. It can quickly store, search and analyze massive amounts of data. Wikipedia, Stack Overflow, Github have adopted it.
Ado, as usual record of my build process.
Installation ElasticSearch
There are several ways to install, I personally still prefer yum CentOS install from source.
Yum installed the CentOS
First to enter the /etc/yum.repos.d
directory, create a file named elasticsearch.repo
source, fill in the following contents:
[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
Here Elastic latest version is 6.2, but the corresponding Elasticsearch-PHP requires PHP version 7.0 or higher. As the company's PHP version 5.x, so only second best, choose a little bit of old versions 5.6.9, 5.x version installed, this step will only need all 6 above the source file content. x 5.x can be replaced.
The next execution
yum install elasticsearch
After installation, the default is the only local service can be accessed, if the need to access the network from another server, also need to open listening range. Enter the installation directory /usr/share/elasticsearch
, edit the elasticsearch.yml
file, modify the following sections:
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
Which network.host
is on the external network access, while path.data
and path.logs
because the default path is not set correctly, there need to manually set it. After the setup is complete path need to check these two directory exists, if there is a residual content in the previous installation directory, the need to back up empty, otherwise it will cause problems.
Then restart the service:
service elasticsearch restart
Installation test
After the reboot is complete, enter in your browser
http://127.0.0.1:9200/?pretty
If you can see the corresponding information indicating a successful installation
Installation LogStash
Then install LogStash service, which is used to summarize all types of log log information to a unified local administration, and here we use this service, because of the need to use it to synchronize data from MySQL to the Elastic.
YUM installed LogStash
This is also the home of Elastic product, and therefore included in the source set up earlier, and now only need to perform the installation:
yum install logstash
This completes the installation. Then do not worry, you also need to install a plugin.
Installation logstash-input-jdbc plug
First to enter the /usr/share/logstash/bin
directory, execute:
./logstash-plugin install logstash-input-jdbc
After the plugin is installed, logstash installation is currently regarded as complete. There are many plug-ins can achieve a variety of feature-rich, but here we say no more.
MySQL data to configure the synchronization Elastic
Then the focus is where the comparison of the configuration data from a MySQL database synchronization to Elastic. First established in any directory synchronization profiles, synchronization scripts I have here is not much, and therefore directly put them perform directory logstash's:
cd /usr/share/logstash/bin
mkdir ktsee
cd ktsee
Then create two files jdbc.conf
and jdbc.sql
which jdbc.conf
are synchronized configuration file, jdbc.sql
MySQL script synchronization. First edit jdbc.conf
, fill in the content:
input {
stdin {
}
jdbc {
# mysql jdbc connection string to our backup databse 后面的ktsee对应mysql中的test数据库
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 这里需要设置正确的mysql-connector-java-5.1.38.jar路径,找不到可以从网上下载后放在配置路径中
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"
# 以下对应着要执行的sql的绝对路径
statement_filepath => "/usr/local/logstash/bin/logstash_jdbc_test/jdbc.sql"
# 定时字段 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新
schedule => "* * * * *"
# 设定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
}
}
It should be noted that where, there is a corresponding note in the above configuration file.
Use Elasticsearch-PHP library integrated into the project
Here choose to use Elasticsearch official PHP library Elasticsearch-PHP, if the project using the composer for packet management, then it is simple, direct mounting to the corresponding version, composer automatically download other dependent libraries. Add code in the project:
$client = \Elasticsearch\ClientBuilder::create()
->setHosts(['192.168.1.1:9200'])
->allowBadJSONSerialization()
->build();
$params = [
'index' => 'ktsee_index',
'_source' => [
"id",
"product_name",
"product_type"
],
'body' => [
'query' => [
'match_phrase_prefix' => [
'product_name' => [
"query" => $post['keyword'],
"slop" => 10
]
],
]
]
];
$response = $client->search($params);
Thus achieving a simple call to ElasticSearch according to the search keyword.
Search Instant achieve prompt code
HTML part:
<form method="get" action="/search" id="header_search">
<input type="text" id="keyword" name="keyword" value="" autocomplete="off" />
<input type="submit" value="" />
</form>
<ul id="header_search_suggest"></ul>
It is worth noting that the search box input control coupled with autocomplete="off"
close native tips drop box, avoid and we are going to do the smart prompt conflict.
CSS part:
#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 part:
var xhr = null;
$('#keyword').bind('input propertychange', function () {
if (xhr) {
xhr.abort();//如果存在ajax的请求,就放弃请求
}
var inputText = $.trim(this.value);
if (inputText != "") { //检测键盘输入的内容是否为空,为空就不发出请求
xhr = $.ajax({
type: 'POST',
url: '/search/suggest',
cache: false,//不从浏览器缓存中加载请求信息
// data: "keyword=" + inputText,
data: {keyword: inputText},
dataType: 'json',
success: function (json) {
//console.log(json);
if (json.count != 0) {
//检测返回的结果是否为空
var lists = "";
$.each(json.data, function (index, obj) {
//处理高亮关键词
var searchContent = obj.product_name;
var suggestItem = '';
if (searchContent.toLowerCase().indexOf(inputText.toLowerCase()) > -1) {
var searchRegExp = new RegExp('(' + inputText + ')', "gi");
suggestItem = searchContent.replace(searchRegExp, ("<strong>$1</strong>"));
}
suggestItem = suggestItem + "<em> - " + obj.product_type + "</em>";
//遍历出每一条返回的数据
lists += "<li class='listName' ><a href='/search/suggest?id=" + obj.id + "&key=" + encodeURI(searchContent + ' - ' + obj.product_type) + "'>" + suggestItem + "</a></li>";
});
$("#header_search_suggest").html(lists).show();//将搜索到的结果展示出来
} else {
$("#header_search_suggest").hide();
}
//记录搜索历史记录
$.post('/search/savesearchlog',{keyword: inputText,count: json.count});
}
});
} else {
$("#header_search_suggest").hide();//没有查询结果就隐藏搜索框
}
}).blur(function () {
setTimeout('$("#header_search_suggest").hide()',500);//输入框失去焦点的时候就隐藏搜索框,为了防止隐藏过快无法点击,设置延迟0.5秒隐藏
});
Demonstration effect
Figure: