PHP上Elasticsearch應用

  • Elasticsearch 是一個建置在 Apache Lucene 上的分散式搜尋和分析引擎。
  • 用於日誌分析、全文搜尋、安全智慧、業務分析和營運智慧使用。
  • Elasticsearch 於 PHP 上應用教學。

What is Elasticsearch?

Elasticsearch是一套基於Apache Lucene(TM)的開源搜尋引擎。無論在開源或專有禮遇,Lucene被認為至今最先進、性能最好、功能最齊全的搜尋引擎。

不過 Elasticsearch不僅僅是Lucene和全文搜尋,我們還能這樣去描述它:

  • 分佈式的實時文進存儲,每個字段都被索引並可被搜尋。
  • 分佈式的實時分析搜尋引擎。
  • 可拓展至上百台服務器,處理PB級結構化或非結構化數據。

環境建置

第一步安裝Elasticsearch環境

安裝ES前請先確認JAVA環境已建置完成,可至CMD下指令 java -version
若無可至JAVA官網進行安裝及環境建置。

Elasticsearch安裝有需多不同方式(待補其他方式)。
此處筆者至Elasticsearch官網直接下載最新版並解壓縮使用。

檔案包安裝好後由CMD直接進入該專案包下指令喚醒Elasticsearch bin/elasticsearch

請注意喚醒ES不可使用root身份進行,並確認專案內部分檔案開放該身份存取(logs等…)

如何確認ES是否安裝成功?
可直接使用網頁連結 http://localhost:9200/ 若出現畫面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name" : "BSQmiuK",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "d6gTLQ0-Svy1WbTWSvKmig",
"version" : {
"number" : "6.2.4",
"build_hash" : "ccec39f",
"build_date" : "2018-04-12T20:37:28.497551Z",
"build_snapshot" : false,
"lucene_version" : "7.2.1",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}

代表大致上沒有問題。

如何在php上應用Elasticsearch?

筆者此處使用[[https://getcomposer.org/|composer]]檔案管理套件進行ES-PHP檔案安裝。
若無此套件可先進行環境建置。

PHP上使用Elasticsearch

先在專案內新增composer.json檔並包含elasticsearch-php(筆者編寫時最新版本需配合php7,固取得版本5.0配合PHP 5.6)。

composer.json檔內容

1
2
3
4
5
{
"require": {
"elasticsearch/elasticsearch": "~5.0"
}
}

完成後cmd到專案目錄下進行 composer install進行套件安裝。

於專案內新增index.php,使用自動加載並實例化客戶端。

1
2
3
4
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;

$client = ClientBuilder::create()->build();

建立索引資歷。將以下code添加至index.php內

1
2
3
4
5
6
7
8
9
10
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'my_id',
'body' => ['testField' => 'abc'],
];


$response = $client->index($params);
var_dump($response);

於網頁執行應該回得到頁面訊息

1
2
3
4
5
6
7
8
9
10
11
12
13
array (size=8)
'_index' => string 'my_index' (length=8)
'_type' => string 'my_type' (length=7)
'_id' => string 'my_id' (length=5)
'_version' => int 6
'result' => string 'updated' (length=7)
'_shards' =>
array (size=3)
'total' => int 2
'successful' => int 1
'failed' => int 0
'_seq_no' => int 5
'_primary_term' => int 1

返回response為Elasticsearch創建索引返回的JSON解碼關聯表。

依條件取得索引資料

1
2
3
4
5
6
7
8
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'my_id',
];

$response = $client->get($params);
var_dump($response);

我們可以依照索引設置及get取得文檔資料

1
2
3
4
5
6
7
8
9
array (size=6)
'_index' => string 'my_index' (length=8)
'_type' => string 'my_type' (length=7)
'_id' => string 'my_id' (length=5)
'_version' => int 1
'found' => boolean true
'_source' =>
array (size=1)
'testField' => string 'abc' (length=3)

依索引刪除資料

1
2
3
4
5
$deleteParams = [
'index' => 'my_index',
];
$response = $client->indices()->delete($deleteParams);
print_r($response);

得到確認回應

1
Array ( [acknowledged] => 1 )

關鍵字搜尋

Elasticsearch可對入稿之資料內容做比對搜尋。

關鍵字若下”後山大火雞”,那”後”、”山”、”大”、”火”、”雞”、”後山”、”火雞”(請自行依此類推)皆會成為搜尋條件並找出一定比重之資料。

讓我們來看看該怎麼做。

首先幫我入稿基本資料:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$params = [
'index' => 'my_index2',
'type' => 'my_type',
'body' => ['count' => '後山大火雞'],
];
$client->index($params);

$params = [
'index' => 'my_index',
'type' => 'my_type',
'body' => ['count' => '火雞'],
];
$client->index($params);


$params = [
'index' => 'my_index',
'type' => 'my_type',
'body' => ['count' => '後山'],
];
$client->index($params);

$params = [
'index' => 'my_index',
'type' => 'my_type',
'body' => ['count' => '後大'],
];
$client->index($params);

搜尋功能應用(其中僅入稿資料”後山” 不再搜尋關鍵字 “大火雞” 拆分比對資料內因故沒被顯示出來)。

1
2
3
4
5
6
7
8
9
$paramsSeach['body'] = array(
'query' => array(
'match' => array(
'count' => '大火雞',
),
)
);
$results = $client->search($paramsSeach);
var_dump($results['hits']['hits']);

上述指令會取得結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
array (size=3)
0 =>
array (size=5)
'_index' => string 'my_index' (length=8)
'_type' => string 'my_type' (length=7)
'_id' => string 'S2fIPmMBYbAZcmkxgr3x' (length=20)
'_score' => float 1.3862944
'_source' =>
array (size=1)
'count' => string '火雞' (length=6)
1 =>
array (size=5)
'_index' => string 'my_index2' (length=9)
'_type' => string 'my_type' (length=7)
'_id' => string 'SmfIPmMBYbAZcmkxgr2d' (length=20)
'_score' => float 0.8630463
'_source' =>
array (size=1)
'count' => string '後山大火雞' (length=15)
2 =>
array (size=5)
'_index' => string 'my_index' (length=8)
'_type' => string 'my_type' (length=7)
'_id' => string 'TWfIPmMBYbAZcmkxg70I' (length=20)
'_score' => float 0.2876821
'_source' =>
array (size=1)
'count' => string '後大' (length=6)

搜尋應用還可對指定索引進行搜尋,於上方資料後山大火雞可發現其陣列內index欄位與其他幾項不同。

此時只要添加索引條件:

1
$paramsSeach['index'] = 'my_index';

由於此處指定搜尋index,故會發現搜尋搜尋結果以濾掉 ['index' => 'my_index2']後山大火雞


以上為Elasticsearch-php基本應用。
其實有許多功能筆者皆未提到。
例: Elasticsearch監聽程式(Elasticsearch-head)、或全域搜尋功能。還有許多分析功能。

待筆者日後對Elasticsearch掌握度更加精進後,在進行文件補充動作


以下附上DB相關進階應用:

DB與ES數據庫連結(conn.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
require_once 'vendor/autoload.php';

//連結MySql資料庫
function get_conn()
{
@$conn = mysql_connect("localhost", "root", "root") or die("error connecting");
mysql_select_db("DBName", $conn); # *DB請自行填入
mysql_query("SET NAMES 'UTF8'");
return $conn;
}

//由DB取得資料並回存ES中
function create_index($maxId, $client)
{
//取捯DB資料
$sql = "SELECT * FROM tableName where id > $maxId limit 0,300"; # *資料表名稱請自行填入
get_conn();
@$result_bugs = mysql_query($sql);
while (@$row = mysql_fetch_assoc(@$result_bugs)) {
$rtn[] = $row;
}

foreach ($rtn as $val) {
$params = array();
$params['body'] = array(
'id' => $val['id'],
'count' => $val['count'], # *請自行修改比對欄位及名稱
);
$params['index'] = 'index';
$params['type'] = 'title';

$client->index($params);
}

return (count($rtn) == 300) ? $val['id'] : false;
}

// set_time_limit(0);
$client = Elasticsearch\ClientBuilder::create()->setHosts(['localhost'])->build();
//刪除所有數據
// $client->indices()->delete(['index' => 'index']);

$a = true;
$maxId = 0;
while ($a) {
$maxId = create_index($maxId, $client);
if (empty($maxId)) {
$a = false;
}
}

執行php(testConn.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
//引入DB連結
require 'conn.php';
require_once 'vendor/autoload.php';
function search($keyword, $page = 0, $size = 20)
{
//實體化對象
$client = Elasticsearch\ClientBuilder::create()->setHosts(['localhost'])->build();
//查詢數據庫拼裝
$params = array();
$params['index'] = 'index';
$params['type'] = 'title';
$params['body']['query']['match']['count'] = $keyword;
$params['from'] = $page;
$params['size'] = $size;

//查詢
$rtn = $client->search($params)['hits'];

//結果組裝
$data['total'] = $rtn['total'];
$data['lists'] = array_column($rtn['hits'], '_source');
$data['lists'] = formartData(array_column($data['lists'], 'id'));

return $data;
}

function formartData($ids)
{
$ids = implode($ids, ',');
$sql = "select * from articles where id in($ids)";
$data = mysql_query($sql);

$rtn = [];
while (@$row = mysql_fetch_assoc(@$data)) {
$rtn[] = $row;
}

return $rtn;
}

$q0 = isset($_GET['q']) ? $_GET['q'] : 'SQL注入';
$num = "15"; //每頁顯示比數
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$offset = ($page - 1) * $num;
$esData = search($q0, $offset, $num);

var_dump($esData);

使用方式:呼叫程式並賦予搜尋值。

1
2
http://localhost/testConn.php?q=

  • 注意1:索引(index)型態(type) 設定時必須小寫。

聲明:此篇教學僅提供學習與交流使用,請勿用於商業用途。

參考資料

Author

LinYoYo

Posted on

2021-11-30

Updated on

2021-12-01

Licensed under