薄洪涛 2019-05-20 11:03:12 14964次浏览 4条评论 16 7 0

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

  1. 需要按照地址去搜索

  2. 按照起止时间去搜索

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

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

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

所以我打开了英文文档和github,这才找到了资料;

  1. 安装扩展
composer require --prefer-dist yiisoft/yii2-elasticsearch

  1. main.php中引入
'elasticsearch' => [
    'class' => 'yii\elasticsearch\Connection',
    'nodes' => [
        ['http_address' => '127.0.0.1:9200'],
    ],
],
  1. 建立model
<?php
namespace app\models;
use yii\elasticsearch\ActiveRecord;
class Merge extends ActiveRecord
{
    //需要返回的字段
    public function attributes()
    {
        return ['contactphone','xxx','xxx']; //其实这里就是你要查询的字段,你要查什么写什么字段就好了
    }
    //索引
    public static function index()
    {
        return 'visit_patient_test_index';
    }
    //文档类型
    public static function type()
    {
        return 'visit_patient_type';
    }
    //这个就是第二步配置的组件的名字(key值)
    public static function getDb()
    {
        return \Yii::$app->get('elasticsearch');
    }
}
  1. 控制器
$merge = new Merge();
$query = $merge::find()->all();  //这句话是查询所有的数据(但是es本身有限制,所以只会查出来10条,下面我会说怎么查更多数据)

这里可能会有如下错误

Elasticsearch Database Exception

TIM截图20190518180829.png

解决方案如下:

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

CURLOPT_HTTPHEADER     => ['Expect:'],

这一行改成

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

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

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

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

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

  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
                ]
            ]
        ]
    ],
];
  1. 单关键词搜索,你只需要讲match对应你要搜索的数组就可以
$query_arr = [
    "bool" => [
        "must" => [
            "match" => ["name"=>"bht"]
        ]
    ],
];
  1. 多关键词搜索,should相当于or,如果想用and,可以改成must
$query_arr = [
    "bool" => [
        "should" => [
            ['match' => ["name" => "bht"]],
            ['match' => ["sex" => "男"]],
            ['match' => ["age" => "24"]],
            ['match' => ["add" => "山东济南"]]
        ],
    ],
];
  1. 范围搜索,对于数字,用gl(great than大于) , lt(less than) , gle(大于等于),lte(小于等于)
$query_arr = [
    "bool" => [
        "filter" => [
            "range" => [
                "xxx" => [
                    "gle" => 10,
                    "lte" => 20
                ]
            ]
        ]
    ],
];
  1. 排序 desc和asc
$sort = ['xxx' => ['order' => 'desc']]
  1. 短语匹配

就是把第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()

希望能对大家有所帮助,详细资料请查看机智的Coder

觉得很赞
  • 评论于 2019-07-12 14:58 举报

    请问一下,我使用的是mysql,怎样用这个es 关联到我的mysql 数据表,直接按照你这个来也不行啊,请指点一下呗

    3 条回复
    评论于 2019-09-11 16:17 回复

    你想把ES的索引当作一张表跟mysql的表做连表操作?怕是不可能哦

    评论于 2019-12-26 11:40 回复

    这个要同步到es里面去 有这种mysql同步的组件

    评论于 2020-10-14 18:05 回复

    这个我真没关联过,这属于跨库关联查询了吧

  • 评论于 2020-05-19 15:41 举报

    model 是最消耗性能的,后台可以用但是如果是接口的话真的不能那么用吧

    1 条回复
    评论于 2020-10-14 18:02 回复

    具体的性能我没测试,不过我觉得,model的性能损耗应该很小,实在不行就直接请求es提供的接口呗

  • 评论于 2021-01-29 12:17 举报

    1.安装elasticsearch的时候,需要用java环境吗,需要再新安装分词吗
    2.我写入到yii框架里边查询无结果,在postman里边直接通过地址localhost:9200/_search查询,传入参数

    `{
    "query": {

    "match": {
      "title": {
        "query": "图书馆"
      }
    }
    

    }
    }`

    是可以搜索到结果的

    1 条回复
    评论于 2021-02-19 17:36 回复

    1.es安装是需要java环境的
    2.请检查yii写法是否正确

  • 评论于 2023-09-16 10:21 举报

    可以直接用Query来实现搜索吗?

您需要登录后才可以评论。登录 | 立即注册