• ES倒排序索引


    前言

    在学习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'];
    }

    执行结果

     

  • 相关阅读:
    算法训练第六十五天|螺旋遍历二维数组
    Java 8 Time API
    拓扑排序及其衍生
    C++设计模式-单例模式
    升降巡检机器人简介
    Android——一个简单的音乐APP(二)
    零基础 从 yolo8 入门计算机视觉超简单:物体识别、图像分类、轨迹追踪、姿势识别
    只有cpu的时候加载模型
    阿里云ACP认证考试易错题集
    [要素察觉]C语言七讲:结构体及C++引用讲解
  • 原文地址:https://blog.csdn.net/weixin_39682289/article/details/127911651