laravel Elasticsearch的搜索操作

Elasticsearch 是一個分布式的搜索和分析引擎,可以用于全文檢索既绩、結(jié)構(gòu)化檢索和分析类咧,并能將這三者結(jié)合起來。Elasticsearch 基于 Lucene 開發(fā)盹愚,是 Lucene 的封裝栅迄,提供了 REST API 的操作接口,開箱即用〗耘拢現(xiàn)在是使用最廣的開源搜索引擎之一毅舆,Wikipedia、Stack Overflow愈腾、GitHub 等都基于 Elasticsearch 來構(gòu)建他們的搜索引擎憋活。

安裝elasticsearch

https://github.com/medcl/elasticsearch-rtf
當(dāng)前的版本是 Elasticsearch 5.1.1,ik 插件也是直接自帶了顶滩。安裝好 ElasticSearch余掖,跑起來服務(wù),測試服務(wù)安裝是否正確:
http://127.0.0.1:9200

安裝laravel以及插件

使用的是laravel5.5框架礁鲁,composer安裝或者官網(wǎng)下載

composer create-project laravel/laravel=5.5 blog 

composer安裝scout

composer require laravel/scout

安裝elasticsearch驅(qū)動

composer require tamayo/laravel-scout-elastic

引入GuzzleHttp包

composer require Guzzlehttp/guzzle

將類引到app.php里面

'providers' => [
    ...
    ...
    Laravel\Scout\ScoutServiceProvider::class,
    ScoutEngines\Elasticsearch\ElasticsearchProvider::class,
]

vendor:publish生成scout配置文件

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

config/scout.php設(shè)置elasticsearch環(huán)境

return [
    'driver' => env('SCOUT_DRIVER', 'elasticsearch'),
    ...
    'elasticsearch' => [
        'index' => env('ELASTICSEARCH_INDEX', 'laravel'),
        'hosts' => [
            env('ELASTICSEARCH_HOST', '127.0.0.1'),
        ],
     ],
];

數(shù)據(jù)部分

migration創(chuàng)建article表盐欺,數(shù)據(jù)方面可以自己填充

php artisan make:migration create_article_table
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticleTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('article', function (Blueprint $table) {
            $table->increments('id');
            $table->text('url');
            $table->string('author', 64)->nullable()->default(null);
            $table->text('title');
            $table->longText('content');
            $table->dateTime('post_date')->nullable()->default(null);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('article');
    }
}

代碼部分

創(chuàng)建article的模板和索引

php artisan make:command InitEs

app/console/command/InitEs.php

namespace App\Console\Commands;

use GuzzleHttp\Client;
use Illuminate\Console\Command;

class InitEs extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'es:init';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Init es to create index';

    /**
     * Create a new command instance.
     *
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $client = new Client();
        $this->createTemplate($client);
        $this->createIndex($client);
    }

    protected function createIndex(Client $client)
    {
        $url = config('scout.elasticsearch.hosts')[0] . ':9200/' . config('scout.elasticsearch.index');
        $client->put($url, [
            'json' => [
                'settings' => [
                    'refresh_interval' => '5s',
                    'number_of_shards' => 1,
                    'number_of_replicas' => 0,
                ],
                'mappings' => [
                    '_default_' => [
                        '_all' => [
                            'enabled' => false
                        ]
                    ]
                ]
            ]
        ]);
    }

    protected function createTemplate(Client $client)
    {
        $url = config('scout.elasticsearch.hosts')[0] . ':9200/' . '_template/rtf';
        $client->put($url, [
            'json' => [
                'template' => '*',
                'settings' => [
                    'number_of_shards' => 1
                ],
                'mappings' => [
                    '_default_' => [
                        '_all' => [
                            'enabled' => true
                        ],
                        'dynamic_templates' => [
                            [
                                'strings' => [
                                    'match_mapping_type' => 'string',
                                    'mapping' => [
                                        'type' => 'text',
                                        'analyzer' => 'ik_smart',
                                        'ignore_above' => 256,
                                        'fields' => [
                                            'keyword' => [
                                                'type' => 'keyword'
                                            ]
                                        ]
                                    ]
                                ]
                            ]
                        ]
                    ]
                ]
            ]
        ]);

    }
}

調(diào)用es腳本

php artisan es:init

創(chuàng)建Article模型
app/Model/Article.php

<?php

namespace App\Model;

//use App\Libraries\EsSearchable;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

/**
 * Class Post
 * @package App
 * @property string $url
 * @property string $author
 * @property string $content
 * @property string $title
 * @property string $post_date
 * @property string $created_at
 * @property string $updated_at
 */
class Article extends Model
{
    use Searchable;
    protected $table = 'article';

    protected $fillable = [
        'url',
        'author',
        'title',
        'content',
        'post_date'
    ];

    public function toSearchableArray()
    {
        return [
            'title' => $this->title,
            'content' => $this->content
        ];
    }
}

導(dǎo)入數(shù)據(jù)模型

php artisan scout:import "App\Model\Article"

新建訪問頁面的控制器 PostController
app\Http\Controllers\PostController

<?php

namespace App\Http\Controllers;

use App\Model\Article;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function search(Request $request)
    {
        $q = $request->get('keyword');
        $paginator = [];
        if ($q) {
            $paginator = Article::search($q)->paginate();
        }
        return view('search', compact('paginator', 'q'));
    }
}

搜索關(guān)鍵詞照顧,變量dump出來的樣子

<pre class="sf-dump" id="sf-dump-609623676" >LengthAwarePaginator</abbr> {#338 ▼ <samp data-depth="1" class="sf-dump-expanded">#total: 1
  #lastPage: 1
  #items: <abbr title="Illuminate\Database\Eloquent\Collection" class="sf-dump-note" style="text-decoration: none; border: none; cursor: help; color: rgb(167, 29, 93);">Collection</abbr> {#340 ▼ <samp data-depth="2" > 
        #attributes: array:9 [▼ <samp data-depth="5" class="sf-dump-expanded">"id" => 52
          "url" => "http://www.baidu.com"
          "author" => "johnny"
          "title" => "紅包"
          "content" => "誰人曾照顧過我的感受"
          "post_date" => "2018-07-19 10:58:35"
          "updated_at" => "2018-07-19 10:58:40"
          "created_at" => "2018-07-19 10:58:42"
          "highlight" => array:2 [▼ <samp data-depth="6" class="sf-dump-expanded">"content.keyword" => array:1 [▼ <samp data-depth="7" class="sf-dump-expanded">0 => "<em>誰人曾照顧過我的感受</em>"</samp> ]
            "content" => array:1 [▼ <samp data-depth="7" class="sf-dump-expanded">0 => "誰人曾<em>照顧</em>過我的感受"</samp> ]</samp> ]</samp> ]
        #original: array:8 [?]
        #changes: []
        #casts: []
        #dates: []
        #dateFormat: null
        #appends: []
        #dispatchesEvents: []
        #observables: []
        #relations: []
        #touches: []
        +timestamps: true
        #hidden: []
        #visible: []
        #guarded: array:1 [?]
        #scoutMetadata: []</samp> }</samp> ]</samp> }
  #perPage: 15
  #currentPage: 1
  #path: "http://blog.com/search"
  #query: array:1 [?]
  #fragment: null
  #pageName: "page"</samp> }</pre>

highlight,也就是高亮需要修改源代碼仅醇,把highlight的json加進(jìn)去
vendor\tamayo\laravel-scout-elastic\src\ElasticsearchEngine

<?php

namespace ScoutEngines\Elasticsearch;

use Laravel\Scout\Builder;
use Laravel\Scout\Engines\Engine;
use Elasticsearch\Client as Elastic;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Collection as BaseCollection;

class ElasticsearchEngine extends Engine
{
    ...
    ...
    ...

    /**
     * Perform the given search on the engine.
     *
     * @param  Builder  $builder
     * @param  array  $options
     * @return mixed
     */
    protected function performSearch(Builder $builder, array $options = [])
    {
        $params = [
            'index' => $this->index,
            'type' => $builder->index ?: $builder->model->searchableAs(),
            'body' => [
                'query' => [
                    'bool' => [
                        'must' => [['query_string' => [ 'query' => "*{$builder->query}*"]]]
                    ]
                ]
            ]
        ];

        $params['body']['highlight']['fields']['*'] = new \stdClass();

        if ($sort = $this->sort($builder)) {
            $params['body']['sort'] = $sort;
        }

        if (isset($options['from'])) {
            $params['body']['from'] = $options['from'];
        }

        if (isset($options['size'])) {
            $params['body']['size'] = $options['size'];
        }

        if (isset($options['numericFilters']) && count($options['numericFilters'])) {
            $params['body']['query']['bool']['must'] = array_merge($params['body']['query']['bool']['must'],
                $options['numericFilters']);
        }
        if ($builder->callback) {
            return call_user_func(
                $builder->callback,
                $this->elastic,
                $builder->query,
                $params
            );
        }

        return $this->elastic->search($params);
    }
    ...
    ...

    /**
     * Map the given results to instances of the given model.
     *
     * @param  mixed  $results
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return Collection
     */
    public function map($results, $model)
    {
        if ($results['hits']['total'] === 0) {
            return Collection::make();
        }

        $keys = collect($results['hits']['hits'])
                        ->pluck('_id')->values()->all();

        $models = $model->whereIn(
            $model->getKeyName(), $keys
        )->get()->keyBy($model->getKeyName());

        return collect($results['hits']['hits'])->map(function ($hit) use ($model, $models) {
            $one = $models[$hit['_id']];
            if (isset($hit['highlight'])) {
                $one->highlight = $hit['highlight'];
            }
            return $one;
        })->filter()->values();
    }
   ...
   ...
 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冗美,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子析二,更是在濱河造成了極大的恐慌粉洼,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叶摄,死亡現(xiàn)場離奇詭異属韧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛤吓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門宵喂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人会傲,你說我怎么就攤上這事锅棕∽驹螅” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵裸燎,是天一觀的道長顾瞻。 經(jīng)常有香客問我,道長德绿,這世上最難降的妖魔是什么荷荤? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮脆炎,結(jié)果婚禮上梅猿,老公的妹妹穿的比我還像新娘。我一直安慰自己秒裕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布钞啸。 她就那樣靜靜地躺著几蜻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪体斩。 梳的紋絲不亂的頭發(fā)上梭稚,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機(jī)與錄音絮吵,去河邊找鬼弧烤。 笑死,一個胖子當(dāng)著我的面吹牛蹬敲,可吹牛的內(nèi)容都是我干的暇昂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼伴嗡,長吁一口氣:“原來是場噩夢啊……” “哼急波!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瘪校,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤澄暮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阱扬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泣懊,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年麻惶,在試婚紗的時候發(fā)現(xiàn)自己被綠了馍刮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡用踩,死狀恐怖渠退,靈堂內(nèi)的尸體忽然破棺而出忙迁,到底是詐尸還是另有隱情,我是刑警寧澤碎乃,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布姊扔,位于F島的核電站,受9級特大地震影響梅誓,放射性物質(zhì)發(fā)生泄漏恰梢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一梗掰、第九天 我趴在偏房一處隱蔽的房頂上張望嵌言。 院中可真熱鬧,春花似錦及穗、人聲如沸摧茴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苛白。三九已至,卻和暖如春焚虱,著一層夾襖步出監(jiān)牢的瞬間购裙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工鹃栽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留躏率,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓民鼓,卻偏偏與公主長得像薇芝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子摹察,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容