一个搜索框,几个包含网页、新闻、图片、视频等在内的选项:这恐怕是目前搜索引擎留给我们大多数人的印象吧。然而,我们今天不讲搜索引擎,而是搜索技术哦~!
搜索,亦称查找,是以 “搜索的精准度”(内容匹配度)和“搜索效率”(搜索耗时)双向界定的技术。技术开发中的耗时偏指,程序员构建搜索程序时的“项目管理时间”和“程序可用的用户等待时间”。
较之Hadoop、Spark和NoSQL数据库如火如荼的发展,搜索——这一最原始、最有用的大数据技术仿佛备受冷落。当被寄予厚望的Spark等技术,随着发展渐显”非万能“的疲态,许多人的关注点便又重归搜索的优化设计。可从以下几个方面着手:
一、数据库优化设计
二、索引文件读取方式的优化设计
三、查找算法的优化设计
四、SQL语句的优化设计
五、客户端代码的优化设计
下面,我们就展开详细论述
一、数据库优化设计
1.对表建立分区
2.针对表中字段建立索引
3.优化存储
…
二、索引文件读取方式的优化设计
1.大文件读取方式的设计
散列映射方式的设计:通过散列或其他方式,将大文件映射为多个小文件,以减轻服务器负担。
多处理方式灵活设计:对大数据映射而来的小文件,选择合适的处理方式:单个逐步处理,并行式处理,多台机器分布式处理等
2.文件读取中缓存方式的优化
统量处理:一次性将所有数据放入缓存中,并进行处理
批量处理:将数据分批次放入缓存,并分批次进行处理。简言之便是,放一部分,取一部分,一批一批处理。
两种处理方式各有利弊,应视情况予以选择。但除此之外,我们还是会有一些发挥的空间,比如缓存的分区块或分片处理,通过分割出来的缓存区块对不同数据的分别处理,实际上便相当于设计出了一个并行处理模式。
3.流类选择及数据传输方式设计
数据传输方式,对应着程序语言相关联的流类,并视程序语言的不同,流处理也会有所区别。一般,主流程序语言对于流类的封装都比较成熟,使得程序语言对性能的优化影响并不大。但是,鉴于语言在系统搭建之初便已被选好,后期更改的空间并不大。
4.大数据读取的输出测试设计
通过每隔一段时间的输出测试,以及时定位问题。
三、查找算法的优化设计
对于大文件,散列查找和二分查找算法,仍是目前主流的实现方式。
鉴于散列算法的限制条件,在散列函数的选取中应着重考虑如下问题:
1、散列函数的选取
2、冲突处理方式
3、P值的选取
4、大文件分割
5、排序算法
其中,对于散列函数及冲突,P值的选取非常关键,越大的P值越能减少冲突,但对应着大量内存的浪费,所以,庞大的数据与有限的内存间便存在一个不小的矛盾。“分而治之”是个值得考虑的策略,即将大文件按照一定规则分割成多个小文件单独处理,但这样一来,不同文件就必须进行单独的排序和查找,也会多消耗一定的时间,具体要看我们如何权衡利弊。
四、SQL语句的优化设计
数据库对海量数据进行查询,我们主要考虑的是尽量避免进行全表查询。具体到SQL语句上来说,一篇文章对此进行了详细的阐述,具体如下(来源:http://blog.fufuok.com/Article/507.aspx):
1.对查询进行优化,应首先考虑在 where 及 order by 涉及的列上建立索引,而尽量避免全表扫描。
2.尽量避免在 where 子句中对字段进行 null 值判断,以降低引擎放弃使用索引而进行全表扫描的几率,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
3.尽量避免在 where 子句中使用!=或<>操作符,以降低引擎放弃使用索引而进行全表扫描的几率。
4.尽量避免在 where 子句中使用or 来连接条件,以降低引擎放弃使用索引而进行全表扫描的几率,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查询也将导致全表扫描:
select id from t where name like '�c%'
若要提高效率,可以考虑全文检索。
7. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
select id from t where num=@num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num=@num
8.尽量避免在 where 子句中对字段进行表达式操作,以降低引擎放弃使用索引而进行全表扫描的几率。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
9.尽量避免在where子句中对字段进行函数操作,以降低引擎放弃使用索引而进行全表扫描的几率。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
应改为:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.尽量避免在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,以降低引擎放弃使用索引而进行全表扫描的几率。
(注:部分内容整合自网络)