1. 程式人生 > >Yii2整合Elasticsearch(二)

Yii2整合Elasticsearch(二)

背景知識:

  1. 全文搜尋可以簡單地分為兩類,一種是順序掃描,即我們常見的使用 like %keyword% 方式,掃描整張資料表,在每一條記錄中查詢;另一種就是索引掃描。elasticsearch就是後者。
  2. 索引掃描分為兩部分:建立索引和搜尋索引。建立索引的主要步驟是:對原資料進行分詞處理(去掉標點和一些無意義的詞等等),將得到的詞元交給語言處理元件(例如將複數變為單數,將過去式變為一般式等等),最後再將詞元交給索引元件建立索引。搜尋索引的主要步驟:對使用者輸入的內容進行分詞語言等處理之後,根據詞元搜尋索引,找到對應的文件id,再根據文件id獲得結果。
  3. logstash可以理解為是一個管道,資料從輸入端傳輸到輸出端,當然你還可以在管道中防止一些濾網來過濾資料,感興趣的讀者可以詳細瞭解一下。
  4. 在使用ES的時候,注意版本,因為版本和版本之間的差距還是很大的
  5. 在操作ES的時候可以考慮使用官方的視覺化工具kibana,或者使用postman,curl命令,當然也可以使用elasticsearch-head,github主頁
  6. 本文基於蘋果系統做介紹。

在上一篇文章中介紹了ES的安裝以及基礎知識,還擴充套件瞭如何使用logstash將mysql的資料匯入到ES中。本文將介紹Yii2框架中如何使用ES。

1.第一步安裝擴充套件:

#區域性安裝
php composer.phar require --prefer-dist yiisoft/yii2-elasticsearch:"~2.0.0"


#全域性安裝
composer require --prefer-dist yiisoft/yii2-elasticsearch:"~2.0.0"


2.在web應用的配置檔案web.php增加如下的配置:

return [
    //....
    'components' => [
        'elasticsearch' => [
            'class' => 'yii\elasticsearch\Connection',
            'nodes' => [
                ['http_address' => '127.0.0.1:9200'],
                // configure more hosts if you have a cluster
            ],
        ],
    ]
];

3.建立一個搜尋類,基於es元件提供的ActiveRecord:

<?php

namespace app\services;
use yii\elasticsearch\ActiveRecord;

class SearchGoods extends ActiveRecord{

    #定義從es中返回結果的欄位
    public function attributes()
    {
        return ['goods_id','name','descr','is_sale','price','sale_price','picture'];
    }

    
    #定義索引
    public static function  index(){
        return 'yii';
    }

    
    #定義文件型別
    public static function type(){
        return 'doc';
    }
}

4.在介紹如何使用上述定義的SearchGoods來進行搜尋之前,先來講一下原生基於API的方式:基於上一篇文章的例子,如果要查詢yii索引下goods型別中name含有“你好”的的文件:

POST http://localhost:9200/yii/goods/_search
{
    "query":{
        "match":{
            "name":"你好"
            }
        }
}

那麼如果我要檢視name或者descr中包含“你好”的文件呢?

POST http://localhost:9200/yii/goods/_search
{
    "query":{
        "multi_match":{
            "query":"你好",
            "fields":["name","descr"]
        }
    }
}

由於我們在上一篇文件中給ES配置了IK分詞,因此我們可以使用IK提供的高亮顯示的功能,例如還是上面的例子,但是要求“你好”這個關鍵字高亮顯示:
 

POST http://localhost:9200/yii/goods/_search
{
    "query":{
        "multi_match":{
            "query":"你好",
            "fields":["title","descr"]
        }
    },
    "highlight" : {
        #左標籤
        "pre_tags" : ["<i>"], 
        #右標籤 
        "post_tags" : ["</i>"],  
        #高亮的欄位
        "fields" : {   
            "descr" : {},
            "name":{}
        }
    }
}
#上面的配置的意思就是:例如有一個文件的內容是{"name":"你好,星期天","descr":"今天天氣真好呀"}
#當你搜索"你好"時,這個文件就會被搜尋出來,並且結果會有一個highlight屬性,值為:
#{"name":"<i>你好</i>,星期天"}
#基於上面的配置,如果想要“你好”在搜尋結果中以紅色顯示,那麼只要在搜尋結果頁中加上如下的css樣式即可:
<style>
    i{
        color:red;
    }
</style>

以上就是原生API的查詢方法,基於這個原理,我們再來看看使用SearchGoods這個類如何做查詢:

<?php


namespace app\controllers;
use app\modules\admin\models\Goods;
use app\services\SearchGoods;
class GoodsController extends BaseController{
    
    #商品控制器中新增基於es搜尋的方法
    public function actionSearch(){
        $hightlight=[

            #左標籤,配合前端.highlight這個類來實現高亮
            "pre_tags"=>['<span class="highlight">'],
            "post_tags"=>['</span>'],

            #在原生api中寫的是{}表示空物件,因此使用php的stdClass來表示空物件
            "fields"=>[
                "name"=>new \stdClass(),
                'descr'=>new \stdClass()
            ]
        ];
        $key=\Yii::$app->request->get('keyword');
        $res=SearchGoods::find()->query([
            'multi_match'=>[
                'query'=>$key,
                "fields"=>['name','descr']
            ]
        ])->highlight($hightlight)->all();
        return $this->render('search',compact('res'));
    }
}

#注意:你完全可以拿SearchGoods這個類當作平常的活動記錄類使用,因為yii\elasticsearch\ActiveRecord這個類也繼承了 yii\db\BaseActiveRecord;

5.以上就是Yii2整合ES的過程,需要注意的點:

  1. 可以將部分欄位資訊存入到ES中,然後根據ES返回的搜尋結果回溯資料表獲取更多的資訊,這種方式效率低但是節省空間。第二種方式就是將需要的所有欄位資訊全部存入到ES中,這種方式就不用回溯資料表了效率高但是空間消耗大
  2. logstash從mysql增量向ES中匯入資料時,如果mysql中資料更新或者新增了都是會同步的,但是如果刪除了logstash並不會在ES中刪除相應的資料。解決方案可以嘗試在資料刪除後手動向ES傳送相應的刪除api請求進行刪除。
  3. 可以在logstash的mysql配置檔案中配置schedule項來實現自動增量