起因

先说说事情的起因,最近在分析数据时经常遇到一种场景,代码需要频繁的读某一张数据库的表,比如根据地区ID获取地区名称、根据网站分类ID获取分类名称、根据关键词ID获取关键词等。虽然以上需求都可以在原始建表时,通过冗余数据来解决。但仍有部分业务存的只是关联表的ID,数据分析时需要频繁的查表。

所读的表存在共同的特点

  • 数据几乎不会变更
  • 数据量适中,从一万到100多万,如果全加载到内存也不太合适。

纠结的地方

在做数据分析时,需要十分频繁的读这些表,每秒有可能需要读上万次。其实内部的数据库集群完全可以胜任,但会对线上业务稍有影响。(你懂得,小公司不可能为离线分析做一套完整的数据存储服务。大部分数据分析还要借助线上的数据集群)

优化方案的思考

有没有一种方式可以不增加线上的压力,同时提供更高效的查询方式?想过redis,但最终选择用文本存储。因为数据分析是一个独立的需求,不希望与现有的redis集群或者其它存储服务有交集。还有一个原因是每次分析的中间结果,对下一次分析并没有很大的实质作用,并不需要把结果持久存储,而且占的内存也会较多。最终使用文本存储,然后用二分来查找。特点,1,存储非常快,虽然redis等nosql服务虽然已经非常快,但仍无法与文本存储相提并论;2,查找的时候使用二分查找,百万条记录查询也可在0.1ms内完成(使用线上的普通硬盘,如果是ssd盘会更快)。

实现步骤

  • 将数据库中需要的字段导出到文本

     方法:使用mysql的phpmyadmin工具,执行sql语句查出主建id和相应字段
    如以上的关键词表: select kid, keyword from keyword
    然后使用phpmyadmin的导出工具,可以快速把结果导出到文本中
    操作截图:
    


  • 将导出的文本(已经按id进行过排序)转换格式重新存储
  • 程序读取转换后的格式

文本存储格式

说明 :需求中,文本每行有两列,第一列是主建ID(数字),第二列为文本。整个文本已经按第一列有序排列,两列之间用tab键分隔。 之前有看过ip.dat的存储,本次仿照其存储格式:将文本中的内容每行转换为固定长度后,存储到新的文件。搜索时,使用文件操作函数fopen,fseek,fgets等函数按字节读取内容,并以二分查找法快速定位需要的内容。

代码实现部分

  • 通用类,类似需求只需要提供符合标准的文本(每行两列,第一列为查找的ID,第二列为文本。同时文本已经按第一列有序排序)
  • 生成以上所提到的存储格式
  • 提供根据id查询接口

代码片断

  • 重新生成新的存储格式

     //读源文件,写入到新的索引文件
    $readfd = fopen($this->filename, 'rb');
    $writefd = fopen($this->formatFile.'_tmp', 'wb+');
    if ($readfd === false || $writefd === false) {
    return false;
    }
    echo "\n start reformat file $this->filename ..";
    while (!feof($readfd)) {
    $line = fgets($readfd, 8192);
    fwrite($writefd, pack("a".$this->maxLength, $line));
    }
    echo "\n reformat ok\n";
    fclose($readfd);
    fclose($writefd);
    rename($this->formatFile.'_tmp', $this->formatFile);
    
  • 二分查找的代码片断

     /**
    * 在索引文件中进行二分查找
    * @param int $id 进行二分查找的id
    * @return [type] [description]
    */
    public function search($key)
    {
    $filesize = filesize($this->formatFile);
    $fd = fopen($this->formatFile, "rb");
    $left = 0; //行号
    $right = ($filesize / $this->maxLength) - 1;
    while ($left <= $right) {
    $middle = intval(($right + $left)/2);
    fseek($fd, ($middle) * $this->maxLength);
    $info = unpack("a*", fread($fd, $this->maxLength))['1'];
    $lineinfo = explode("\t", $info, 2);
    if ($lineinfo['0'] > $key) {
    $right = $middle - 1;
    } elseif ($lineinfo['0'] < $key) {
    $left = $middle + 1;
    } else {
    return $lineinfo['1'];
    }
    }
    return false;
    }
    
  • 整个类库代码一共91行,具体可查看github的demo代码 ,相关链接

运行截图

以上拿100万的关键词进行测试,根据关键词id快速查找关键词,平均速度可以达到0.1毫秒。

PHP实现文本快速查找 - 二分查找法相关推荐

  1. 【Golang第6章:排序和查找】golang怎么排序,golang的顺序查找和二分查找,go语言中顺序查找二分查找介绍和案例

    介绍 这个是在B站上看边看视频边做的笔记,这一章是GO语言的排序和查找 有golang怎么排序,golang的顺序查找和二分查找,go语言中顺序查找二分查找介绍和案例,具体请看[文章目录] 配套视频自 ...

  2. Python查找-二分查找

    Python查找-二分查找 二分查找 折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务. 它的基本思想是,将n个元素分成个数大致相 ...

  3. 数据结构与算法(8-2)有序表查找(折半查找(二分查找)、插值查找)

    目录 一.折半查找(二分查找) 二.插值查找 总代码 一.折半查找(二分查找) 原理:一次次折半,不断向着查找值的位置靠近 . 适用场景:有序(必须) 流程:开始时,min标志首,max标志尾,med ...

  4. C语言之折半查找(二分查找)

    一.什么是折半查找? 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中 ...

  5. Java实现折半查找(二分查找)的递归和非递归算法

    Java二分查找实现,欢迎大家提出交流意见. /** *名称:BinarySearch *功能:实现了折半查找(二分查找)的递归和非递归算法. *说明: *     1.要求所查找的数组已有序,并且其 ...

  6. java查找一个数等于一组数中哪些数字相加的和_快速入门二分查找

    二分查找 使用二分查找的前提 模板 常见的二分查找应用比如猜数字游戏. // 二分查找适用于有序的数组 // 这个一个最简单的二分查找算法,前提是数组中不存在重复元素 function binaryS ...

  7. Java数据结构与算法——线性查找 二分查找 插值查找

    1.线性查找 有一个数列: {1,8, 10, 89, 1000, 1234} ,判断数列中是否包含此名称[顺序查找] 要求: 如果找到了,就提示找到,并给出下标值. package com.szh. ...

  8. 数据结构 | 折半查找 /二分查找 算法细节、二分查找判定树

    一.基本思想 假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步 ...

  9. leetcode 274, 275. H-Index I, II(H 指数问题合集,线性查找/二分查找)

    274. H-Index https://leetcode.com/problems/h-index/ 题解 第一遍没看懂题目.看了中文版的题目才明白,是要找到 h,满足总共有 h 篇论文分别被引用了 ...

最新文章

  1. Web service到底是什么?
  2. 光纤通信及周边产品知识汇总
  3. SpringCloud_项目搭建以及Eureka
  4. python都可以干什么-python都能干嘛
  5. Java多线程系列--“基础篇”09之 interrupt()和线程终止方式
  6. easyui datagrid 后台分页,前端如何处理
  7. 【转】DB2 常用命令
  8. SU编程和Madagascar编程中的函数对比和区别--终端提示函数
  9. python为csv文件添加表头_python读csv文件时指定行为表头或无表头的方法
  10. 日志收集系统Elasticsearch,Fluentd , Kibana
  11. FPGA 20个例程篇:7.FLASH读写断电存储
  12. 倍福TwinCAT 3 气缸动作程序编写
  13. 删除桌面上的天猫双十一图标
  14. 字节跳动的“飞阅会”开会模式:先笔谈 后PK 直接生成会议纪要
  15. Android Studio MAC M1 安装模拟器
  16. 百面机器学习 自学笔记
  17. Photoshop支持ICO图片格式(咋个办呢 zgbn)
  18. beeline客户端连接hiveserver2问题
  19. android dataBinding 与ObservableField实现双向绑定
  20. shader 雪 顶点位移_游戏雪天效果·积雪的厚度

热门文章

  1. 外企九年-我最终选择放弃
  2. checkmarx使用笔记、原理
  3. 2019 全球智博会即将开幕,五大惊喜抢先看!| 智博会
  4. uniapp 输入法画面_表单输入绑定 · uni-app跨平台移动应用开发 · 看云
  5. 【详细】小程序搜索功能实现
  6. Golang GO语言 IDE推荐 主流IDE 特点分析 下载链接 教程 (1)
  7. Codeforces Round #549 (Div. 2) D. The Beatles
  8. 什么叫.NET ? (来源: 清华大学出版社)
  9. [转载]DBA的特质第二部分:性格
  10. Windows 10 与 kali 双系统安装