前几天做了一个模块,大数据的搜索,其实也不是特别大,组合起来差不多800万左右,用的是mysql数据库,需求有这么变态的两点;
需要按照地址去搜索
按照起止时间去搜索
别的不说,就这两条,mysql也就只能用like了吧,而且地址需要用%xx%这种,压根用不到索引,结果可想而知,服务器直接崩了;
和老大讨论了下,决定采用ElasticSearch做全文搜索,由于之前看过一点点(其实就是自己瞎玩),所以学起来不是太难,但是学过和做过东西是不一样的两个概念;所以写下这篇文章记录下需要注意的点,而且也是为了弥补百度ElaticSearch资料空白;
首先就是框架的选用,这里我选用的是Yii2.0,这里吐槽下Yii2.0的文档,中文文档里压根就没有ElasticSearch,打开直接404,
所以我打开了英文文档和github,这才找到了资料;
第一步,需要安装扩展
composer require --prefer-dist yiisoft/yii2-elasticsearch
第二步,main.php中引入
'elasticsearch' => [ 'class' => 'yii\elasticsearch\Connection', 'nodes' => [ ['http_address' => '127.0.0.1:9200'], ], ]
第三步,建立model
<?php namespace app\models; use yii\elasticsearch\ActiveRecord; class Merge extends ActiveRecord { //需要返回的字段 public function attributes() { return ['xxx', 'xxx', 'xxx', 'xxx']; } //索引 public static function index() { return 'visit_patient_index'; } //文档类型 public static function type() { return 'visit_patient_type'; } public static function getDb() { return \Yii::$app->get('elasticsearch'); } }
第四步,控制器
$merge = new Merge(); $query = $merge::find()->all(); //这句话是查询所有的数据(但是es本身有限制,所以只会查出来10条,下面我会说怎么查更多数据)
这里可能会有如下错误
Elasticsearch Database Exception
解决方案如下:
打开yii2-advanced/vendor/yiisoft/yii2-elasticsearch/Connection.php这个文件,修改扩展的源码
CURLOPT_HTTPHEADER => ['Expect:'],
这一行改成
CURLOPT_HTTPHEADER => [ 'Accept: application/json', 'Content-Type: application/json' ],
解下来就是全文搜索的重点了;
mysql这种数据库不支持全文搜索,一搜就崩;上次服务器搞崩了凌晨到维护好;
这里全文搜索有以下几个坑,需要注意
如果你按照时间搜索的话,记得字段的类型,一定要指定为date类型,不要问我怎么知道的,表不是我建的,但是坑了我一下午,就是不能按照时间范围搜索;
单搜索词和多个搜索词写法不一样,需要注意;
es搜索,默认返回10条语句,但是你可以使用limit()去限制查询出的结果,比如你希望100条,你就limit(100),但是上限是1w;
代码开始:
时间范围搜索,xxx是你要搜的字段,start是开始时间,end是结束时间,注意xxx的字段类型一定是date,xxx和start,end结构一致;
$query_arr = [ "bool" => [ "filter" => [ "range" => [ "xxx" => [ "from" => $start, "to" => $end ] ] ] ], ];
2. 单关键词搜索,你只需要讲match对应你要搜索的数组就可以
$query_arr = [ "bool" => [ "must" => [ "match" => ["name"=>"bht"] ] ], ];
3.多关键词搜索,should相当于or,如果想用and,可以改成must
$query_arr = [ "bool" => [ "should" => [ ['match' => ["name" => "bht"]], ['match' => ["sex" => "男"]], ['match' => ["age" => "24"]], ['match' => ["add" => "山东济南"]] ], ], ];
4.范围搜索,对于数字,用gl(great than大于) , lt(less than) , gle(大于等于),lte(小于等于)
$query_arr = [ "bool" => [ "filter" => [ "range" => [ "xxx" => [ "gle" => 10, "lte" => 20 ] ] ] ], ];
5.排序 desc和asc
$sort = ['xxx' => ['order' => 'desc']]
6.短语匹配
就是把第3条中的match改成match_phrase,在执行短语匹配查询时,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变;个人感觉比精确匹配更好用
以上条件写好后,按照如下,就可以搜索了
$merge = new Merge(); $merge::find()->query($query_arr)->orderBy($sort)->asArray()->all()
但是搜索出来的数目只有10条,如果你的数据多于10条,请加limit(你想显示的条数)
query->orderBy($sort)->asArray()->limit(100)->all()
最后测试了下es搜索的性能,千万级的数据,搜索条件大约8-9个,全部模糊搜索,搜索返回数据设置100条,搜索时间为54ms!!!
忙活了几天,终于完成了这个功能了,明天准备上线,晚安!
希望能对大家有所帮助;