首页 技术PHP正文

Elasticsearch第三篇之全文搜索及在Yii2.0中的使用

薄洪涛 PHP 2019-05-17 4507 1 ElasticsearchYii2.0

前几天做了一个模块,大数据的搜索,其实也不是特别大,组合起来差不多800万左右,用的是mysql数据库,需求有这么变态的两点;

  1. 需要按照地址去搜索

  2. 按照起止时间去搜索

别的不说,就这两条,mysql也就只能用like了吧,而且地址需要用%xx%这种,压根用不到索引,结果可想而知,服务器直接崩了;

和老大讨论了下,决定采用ElasticSearch做全文搜索,由于之前看过一点点(其实就是自己瞎玩),所以学起来不是太难,但是学过和做过东西是不一样的两个概念;所以写下这篇文章记录下需要注意的点,而且也是为了弥补百度ElaticSearch资料空白;

首先就是框架的选用,这里我选用的是Yii2.0,这里吐槽下Yii2.0的文档,中文文档里压根就没有ElasticSearch,打开直接404,

image.png

所以我打开了英文文档和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

image.png

解决方案如下:

打开yii2-advanced/vendor/yiisoft/yii2-elasticsearch/Connection.php这个文件,修改扩展的源码

CURLOPT_HTTPHEADER     => ['Expect:'],

这一行改成

CURLOPT_HTTPHEADER => [
    'Accept: application/json',
    'Content-Type: application/json'
],

解下来就是全文搜索的重点了;

mysql这种数据库不支持全文搜索,一搜就崩;上次服务器搞崩了凌晨到维护好;

这里全文搜索有以下几个坑,需要注意

  1. 如果你按照时间搜索的话,记得字段的类型,一定要指定为date类型,不要问我怎么知道的,表不是我建的,但是坑了我一下午,就是不能按照时间范围搜索;

  2. 单搜索词和多个搜索词写法不一样,需要注意;

  3. es搜索,默认返回10条语句,但是你可以使用limit()去限制查询出的结果,比如你希望100条,你就limit(100),但是上限是1w;

代码开始:

  1. 时间范围搜索,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!!!

忙活了几天,终于完成了这个功能了,明天准备上线,晚安!

希望能对大家有所帮助;

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论

精彩评论