懶人包
比對方式:
- TERM : 完全符合。
- MATCH : 拆字,模糊搜尋。
- MATCH_PHRASE : 不拆字,模糊搜尋。
- MATCH_PHRASE_PREFIX : 不拆字,精準,模糊搜尋。
搜尋條件:
- must : 多項查詢條件完全匹配,相當於 AND。
- must_not : 多個查詢條件相反匹配,相當於 NOT。
- should : 至少有一個條件匹配,相當於 OR。
因為筆者比較喜歡看到東西能動,再去了解他為什麼可以動。
所以此處我們先做一個小範例(此處不在教學環境建置及套件載入,各位讀者請自行各顯神通讓程式碼能動)。
搜尋精準度
讓我們先放置資料進 ES 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
require 'vendor/autoload.php'; use Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()->build();
$params = [ 'index' => 'my_index2', 'type' => 'my_type', 'id' => 1, 'body' => ['count' => '後山大火雞'], ]; $client->index($params);
$params = [ 'index' => 'my_index2', 'type' => 'my_type', 'id' => 2, 'body' => ['count' => '後山大火災'], ]; $client->index($params);
|
在下搜尋指令
1 2 3 4 5 6 7 8 9 10
| $paramsSeach['index'] = 'my_index2'; $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
| /Applications/MAMP/htdocs/jesda/es/index.php:97: array (size=2) 0 => array (size=5) '_index' => string 'my_index2' (length=9) '_type' => string 'my_type' (length=7) '_id' => string '1' (length=1) '_score' => float 0.5753642 '_source' => array (size=1) 'count' => string '後山大火雞' (length=15) 1 => array (size=5) '_index' => string 'my_index2' (length=9) '_type' => string 'my_type' (length=7) '_id' => string '2' (length=1) '_score' => float 0.2876821 '_source' => array (size=1) 'count' => string '後山大火災' (length=15)
|
怪了?我搜尋火雞
關你後山大火災
屁事。
對於 ES 有基本程度了解都知道,因為 ES 進行了字詞切割
並比對搜尋。
那如果我們就是想要搜尋火雞
就好,那怎麼辦呢?
讓我們將指令內 match
替換成 match_phrase
試試看。
代碼如下:
1 2 3 4 5 6 7 8 9 10
| $paramsSeach['index'] = 'my_index2'; $paramsSeach['body'] = array( 'query' => array( 'match_phrase' => array( 'count' => '火雞', ), ) ); $results = $client->search($paramsSeach); var_dump($results['hits']['hits']);
|
你將會看到,結果只剩下後山大火雞
,而火災呢? 天要下雨娘要嫁人,隨它去吧~
對此搜尋關鍵字筆者有找到幾個比較常用的可以做一下介紹。
在此特別提一下 MATCH_PHRASE
與 MATCH_PHRASE_PREFIX
。
兩者差別在於,MATCH_PHRASE
在文章內搜尋關鍵字比重過低情況下該文檔會被忽略。而 MATCH_PHRASE_PREFIX
可解決這個問題。
當然還有調整搜尋的精準度可以進行調整,但此時筆者功力太淺。先以此解法解決部分文檔因為搜尋比重太低而被忽略問題了。
看到這裡可能會有人覺得,那我可不可以對文檔內資料做複合式
搜尋。
猶如 SQL 指令 AND、OR、NOT IN 等等,要 A 要 B 不要 C。
有!都有! 讓我們繼續往下走。
複合式搜尋
在此我們先將資料洗一下。
讓我們來見識 NBA 大名鼎鼎的四位球員(文章主軸不是探討 NBA 球員,故只取球員部分生涯數據 )。
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
| $params = [ 'index' => 'nba', 'type' => 'nba', 'id' => 1, 'body' => [ 'name' => 'Kobe Bryant', 'position' => '後衛', 'glory' => '總冠軍 最有價值球員 得分王 全明星賽 神' ], ]; $client->index($params);
$params = [ 'index' => 'nba', 'type' => 'nba', 'id' => 2, 'body' => [ 'name' => 'Steve Nash', 'position' => '後衛', 'glory' => '最有價值球員 助攻王 全明星賽' ], ]; $client->index($params);
$params = [ 'index' => 'nba', 'type' => 'nba', 'id' => 3, 'body' => [ 'name' => 'LeBron James', 'position' => '前鋒', 'glory' => '總冠軍 最有價值球員 得分王 全明星賽' ], ]; $client->index($params);
$params = [ 'index' => 'nba', 'type' => 'nba', 'id' => 4, 'body' => [ 'name' => 'Shaquille O\'Neal', 'position' => '中鋒', 'glory' => '總冠軍 最有價值球員 得分王 全明星賽' ], ]; $client->index($params);
|
讓我們看一下,ES 提供的搜尋條件有哪些:
- must : 多項查詢條件完全匹配,相當於 AND。
- must_not : 多個查詢條件相反匹配,相當於 NOT。
- should : 至少有一個條件匹配,相當於 OR。
讓我們來看看如何使用。
先來最簡單的,找出得過 最有價值球員
榮耀的。
1 2 3 4 5 6 7 8 9 10
| $paramsSeach['index'] = 'nba'; $paramsSeach['body'] = array( 'query' => array( 'match_phrase' => array( 'glory' => '最有價值球員', ), ) ); $results = $client->search($paramsSeach); var_dump($results['hits']['hits']);
|
結果輸出是四位球員,那如果要同時擁有 最有價值球員
與 得分王
呢?
1 2 3 4 5 6 7 8 9 10 11 12 13
| $paramsSeach['index'] = 'nba'; $paramsSeach['body'] = array( 'query' => [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '最有價值球員'], 'match_phrase' => ['glory' => '得分王'], ], ], ], ); $results = $client->search($paramsSeach); var_dump($results['hits']['hits']);
|
這邊直接將搜尋條件 query
內應用換掉,讓他可以達成 最有價值球員
AND 得分王
的搜尋條件。
可以看到 Steve Nash
被篩選掉了。
小叮嚀:若是搜尋類型使用 match
因為會幫你拆字搜尋,所以 得分王
/助攻王
都會被條件找出來。導致沒有達到此處想要的效果。
這邊想要或是 只要得過 助攻王
的就被顯示出來。 等同搜尋條件上的 OR。
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
| $paramsSeach['index'] = 'nba'; $paramsSeach['body'] = array( 'query' => [ 'bool' => [ 'should' => [ [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '最有價值球員'], 'match_phrase' => ['glory' => '得分王'], ], ], ], [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '助攻王'], ], ], ] ] ],
], ); $results = $client->search($paramsSeach); var_dump($results['hits']['hits']);
|
這邊組成比較複雜一些,我們可以將搜尋條件看成:
1 2 3
| $bool['bool']['msut'] => [ 'match_phrase' => ['glory' => '最有價值球員'], ];
|
在一個一個放入 should
的陣列中,就能在裡面形成 OR
的條件效果。
仔細想想,把 神
放入凡人中是不是太不公平了些,我們這邊就將 神
排除掉(添加條件 must_not
)。
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
| $paramsSeach['index'] = 'nba'; $paramsSeach['body'] = array( 'query' => [ 'bool' => [ 'should' => [ [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '最有價值球員'], 'match_phrase' => ['glory' => '得分王'], ], ], ], [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '助攻王'], ], ], ] ], 'must_not' => [ 'match_phrase' => ['glory' => '神'], ], ],
], ); $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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| # 加了這段 [ 'match' => [ 'position' => [ 'query' => '前鋒 後衛', 'operator' => 'or', ], ], ],
$paramsSeach['index'] = 'nba'; $paramsSeach['body'] = array( 'query' => [ 'bool' => [ 'should' => [ [ 'bool' => [ 'must' => [ ['match_phrase' => ['glory' => '最有價值球員']], ['match_phrase' => ['glory' => '得分王']], [ 'match' => [ 'position' => [ 'query' => '前鋒 後衛', 'operator' => 'or', ], ], ], ], ], ], [ 'bool' => [ 'must' => [ 'match_phrase' => ['glory' => '助攻王'], ], ], ] ], 'must_not' => [ 'match_phrase' => ['glory' => '神'], ], ],
], ); $results = $client->search($paramsSeach); var_dump($results['hits']['hits']);
|
本來預想篩選出 position
是 前鋒
或 後衛
的資料。但因 match
關係 前鋒
會被進行拆字搜尋。
待筆者日後 ES 精進了再來進行編寫。
聲明:此篇教學僅提供學習與交流使用,請勿用於商業用途。
參考資料
Elasticsearch 学习笔记(一)
初窥 Elasticsearch-PHP [1.0]