Elasticsearch第三篇之全文搜索及在Yii2.0中的使用
前几天做了一个模块,大数据的搜索,其实也不是特别大,组合起来差不多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!!!
忙活了几天,终于完成了这个功能了,明天准备上线,晚安!
希望能对大家有所帮助;