前言
在学习Elasticsearch的使用前,我们先来了解下es是如何实现全文搜索的。
倒排索引是 Elasticsearch 中非常 重要的索引结构,从 文档单词到文档 ID 的过程
为什么要使用倒排索引
先看下面的商品数据goods
| id | 标题 | 描述 |
| 1 | 小米手机 | 小米手机性价比贼高,为发烧而生 |
| 2 | 苹果手机 | 高端手机,生态丰富 |
| 3 | 三只松鼠零食大礼包 | 便宜实惠,高端品牌质量有保证 |
| 4 | 小米电脑 | 小米电脑性价比贼高,便宜好用 |
如果我们要模糊查含有手机关键词的商品,以mysql查询为例,应该是下面的语句
select * from goods where 标题 like '%手机%' or 描述 like '%手机%'
了解mysql的都知道,用上面的语句查询,索引会失效导致全表查询,如果数据量大的话就会很慢很慢。
怎么解决呢?用倒排索引
倒排索引原理
倒排索引主要包含两个过程:创建倒排索引、倒排索引搜索
创建倒排索引
先对 文档的内容进行分词,形成一个个的 token,也就是 单词,然后保存这些 token 与文档的对应关系。
如上面的商品数据goods,保存后如下所示
| token | 对应文档 |
| 小米 | 1,4 |
| 手机 | 1,2 |
| 苹果 | 2 |
| 电脑 | 4 |
| 三只松鼠 | 3 |
| 零食 | 3 |
| 大礼包 | 3 |
| 便宜 | 3,4 |
| 性价比 | 1,4 |
| ... | ... |
倒排索引搜索
对搜索词先分词,得到多个Token,然后去倒排索引中进行匹配
如搜索词:性价比手机
分词后:性价比、手机
性价比匹配到的文档是1、4;手机匹配到的文档是1、2
最终搜索到的文档就是1
| 1 | 小米手机 | 小米手机性价比贼高,为发烧而生 |
实践
简单实现下倒排索引的搜索引擎,中文分词比较麻烦,这里先使用英文,默认英文分词都是空格。
搜索引擎类
class SearchEngines
{
// 搜索数据
private $searchData;
// 搜索
public function search($keyword)
{
// 转小写
$keyword = strtolower($keyword);
// 对搜索词进行分词
$keywords = explode(' ', $keyword);
$ids = [];
foreach ($keywords as $keyword) {
// 查找搜索词对应文档
$tmpIds = [];
foreach ($this->searchData[$keyword] as $id) {
$tmpIds[] = $id;
}
// 第一个不取交集
if (!$ids) {
$ids = $tmpIds;
continue;
}
// 取搜索词对应文档的交集
$ids = array_intersect($ids, $tmpIds);
}
return $ids;
}
// 插入数据
public function save($id, $keyword)
{
// 对关键词进行分词
$keywords = explode(' ', $keyword);
foreach ($keywords as $keyword){
// 都改为小写
$keyword = strtolower($keyword);
if (!isset($this->searchData[$keyword])) {
$this->searchData[$keyword] = [];
}
if (!in_array($id, $this->searchData[$keyword])) {
$this->searchData[$keyword][] = $id;
}
}
}
}
数据插入
$insertData = [
1 => [
'id' => 1,
'title' => 'Xiaomi phones',
'desc' => 'Xiaomi\'s mobile phone is more cost-effective than thieves, and is born of fever'
],
2 => [
'id' => 2,
'title' => 'iPhone',
'desc' => 'High end mobile phones with rich ecology'
],
3 => [
'id' => 3,
'title' => 'Three Squirrels Snack Pack',
'desc' => 'food'
],
4 => [
'id' => 4,
'title' => 'Xiaomi Computer',
'desc' => 'Xiaomi computers are more cost-effective than thieves, and cheap and easy to use'
]
];
$searchEngines = new SearchEngines();
foreach ($insertData as $data) {
$searchEngines->save($data['id'], $data['title']." ".$data['desc']);
}
关键词搜索
$ids = $searchEngines->search('cost-effective phone');
foreach ($ids as $id) {
echo $insertData[$id]['title'];
}
执行结果



















