全文搜索用elasticsearch太佔資源了,而且速度慢。換換換換換換換。(退錢~~~~)
安裝 meilisearch
# https://github.com/meilisearch/MeiliSearch/releases
wget https://github.com/meilisearch/MeiliSearch/releases/download/v0.23.1/meilisearch-linux-amd64
mv meilisearch-linux-amd64 /usr/local/bin/meilisearch
mkdir /data/meilisearch_db
#運行
/usr/local/bin/meilisearch --db-path /data/meilisearch_db
#生產使用
/usr/local/bin/meilisearch --db-path /data/meilisearch_db --no-analytics=true --env production --master-key meili_password
文檔
https://docs.meilisearch.com/reference/
推薦直接用官方的sdk,curl調用的麻煩,還老寫錯了 :)
php sdk
https://github.com/meilisearch/meilisearch-php
composer require meilisearch/meilisearch-php guzzlehttp/guzzle http-interop/http-factory-guzzle:^1.0
use MeiliSearch\Client;
$client = new Client('http://127.0.0.1:7700', 'masterKey');
// 舉個例子
// 全市的醫院
// hospitals
// id // 編號
// name // 醫院名稱
// level // 醫院等級
// district // 所在市區
// address // 地址
// _geo // 座標
// 如果存在則刪除documents
$client->deleteIndexIfExists('hospitals');
// 創建documents
// primaryKey 指定主鍵 (我測試時 不指定主鍵 文檔裏如果有多個整數字段 會使用最後一個整數字段)
$client->createIndex('hospitals', ['primaryKey' => 'id']);
$index = $client->index('hospitals');
// 可過濾 (類似sql的 where)
$index->updateFilterableAttributes([
'level',
'district',
]);
// 可排序 ( 'id:desc', '_geoPoint(31.960546780595564, 118.88298329046941):asc')
$index->updateSortableAttributes([
'id',
'_geo',
]);
// 可全文搜索的字段 (不設置 默認所有字段都可以全文搜索)
$index->updateSearchableAttributes([
'name',
]);
// 添加或者替換文檔
$documents = [
['id' => 1, 'name' => "南京鼓樓醫院", 'level' => '三甲', 'district' => '鼓樓區', 'address' => '江蘇省南京市鼓樓區中山路348號', '_geo' => ['lat' => 32.060869, 'lng' => 118.789666]],
['id' => 2, 'name' => "南京市江寧醫院(湖山路院區)", 'level' => '三甲', 'district' => '江寧區', 'address' => '南京市江寧區湖山路169號', '_geo' => ['lat' => 31.961168, 'lng' => 118.876076]],
];
$index->addDocuments($documents);
// 查詢例子
// 搜索醫院名
$query = '醫院';
$options = [];
$index->search($query, $options)->getHits();
// 過濾出江寧區的醫院,且等級是三甲的
$options = [
'filter' => [ "district = '江寧區'", "level = '三甲'"],
];
// 按指定座標排序
$options = [
'sort' => [
"_geoPoint(31.960546780595564, 118.88298329046941):asc",
],
];
// 只返回指定字段, 默認返回所有字段
$options = [
'attributesToRetrieve' => ['id', 'name'],
];
// 搜索關鍵詞 高顯返回 如 搜索 "醫院" 返回的 ['_formatted']['name'] "南京鼓樓<em>醫院</em>“
$options = [
'attributesToHighlight' => ['name'],
];
// 搜索關鍵詞 返回精確的字符串索引 如 搜索 "醫院" 返回的 ['_matchesInfo']['name'] ['start' => 11, 'lenght' => 6]
$options = [
'matches' => true,
];
// 可以根據'_matchesInfo' 分割成數組 ([0, string] [1, string] 1代表當前是關鍵詞)
function _split_by_matchesInfo($str, $matches) {
$arr = [];
$last = 0;
$len = strlen($str);
foreach($matches as $index => $range) {
if ($last < $range['start']) {
$arr[] = [0, substr($str, $last, ($range['start'] - $last))];
}
$arr[] = [1, substr($str, $range['start'], $range['length'])];
$last = $range['start'] + $range['length'];
}
if($last < ($len - 1)) {
$arr[] = [0, substr($str, $last)];
}
return $arr;
}
// 統計可過濾字段的數量 (類似 elastic 查詢的 aggs)
// 需要注意的是 facetsDistribution 字段 一定是可過濾的(updateFilterableAttributes)
$options = [
'facetsDistribution' => ['district'],
];
$result = $index->search('', $options);
$facets = $result->getFacetsDistribution();
// 返回
$facets['district'] = [
'江寧區' => 1,
'鼓樓區' => 1,
]
對於簡單的過濾統計 基本上可以替換掉es
相同的數據 佔用內存比較下哈