只需五步骤:

  1. 启动 集成ik中文分词插件的Elasticsearch7.9 Docker镜像
  2. Laravel7 配置 Scout
  3. 配置 Model模型
  4. 导入数据
  5. 搜寻

演示地址

https://www.ar414.com

搜寻范畴

  • 文章内容
  • 题目
  • 标签

后果权重

  1. 呈现关键词数量
  2. 呈现关键词次数

搜寻页面

  • 高亮显示
  • 分词显示
  • 后果分页

前言

次要是博客刚好想做个搜寻,顺便就整顿成文章

Laravel + Elasticsearch 很多前辈都写过教程和案例,然而随着Elasticsearch和laravel的版本升级 以前的文章很多都不实用新版本的,倡议大家应用任何开源我的项目时应该过一遍文档以以后应用的版本文档为主,教程为辅

  • Elasticsearch 7.9
  • Laravel 7
  • elasticsearch-analysis-ik v7.9

参考

  • ik 中文分词插件
  • elasticsearch 官网文档

应用集成ik中文分词插件的Elasticsearch

拉取docker

$ docker pull ar414/elasticsearch-7.9-ik-plugin

创立日志和数据存储目录

本地映射到docker容器内,避免docker重启数据失落
$ mkdir -p /data/elasticsearch/data$ mkdir -p /data/elasticsearch/log$ chmod -R 777 /data/elasticsearch/data$ chmod -R 777 /data/elasticsearch/log

运行

docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -v /data/elasticsearch/data:/var/lib/elasticsearch -v /data/elasticsearch/log:/var/log/elasticsearch ar414/elasticsearch-7.9-ik-plugin 

验证

$ curl http://localhost:9200{  "name" : "01ac21393985",  "cluster_name" : "docker-cluster",  "cluster_uuid" : "h8L336qcRb2i1aydOv04Og",  "version" : {    "number" : "7.9.0",    "build_flavor" : "default",    "build_type" : "docker",    "build_hash" : "a479a2a7fce0389512d6a9361301708b92dff667",    "build_date" : "2020-08-11T21:36:48.204330Z",    "build_snapshot" : false,    "lucene_version" : "8.6.0",    "minimum_wire_compatibility_version" : "6.8.0",    "minimum_index_compatibility_version" : "6.0.0-beta1"  },  "tagline" : "You Know, for Search"}

测试中文分词

curl -X POST "http://localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d'{  "analyzer": "ik_max_word",  "text":     "laravel天下无敌"}'{  "tokens" : [    {      "token" : "laravel",      "start_offset" : 0,      "end_offset" : 7,      "type" : "ENGLISH",      "position" : 0    },    {      "token" : "天下无敌",      "start_offset" : 7,      "end_offset" : 11,      "type" : "CN_WORD",      "position" : 1    },    {      "token" : "天下",      "start_offset" : 7,      "end_offset" : 9,      "type" : "CN_WORD",      "position" : 2    },    {      "token" : "无敌",      "start_offset" : 9,      "end_offset" : 11,      "type" : "CN_WORD",      "position" : 3    }  ]}

Laravel 我的项目中应用 Elasticsearch


Elasticsearch官网有提供 SDK,在 Laravel 我的项目中能够更加优雅疾速的接入 Elasticsearch,Laravel 自身有提供 Scout全文搜寻 的解决方案,咱们只需将默认的 Algolia 驱动 替换成ElasticSearch驱动

装置

  • laravel/scout
  • matchish/laravel-scout-elasticsearch
$ composer require laravel/scout$ composer require matchish/laravel-scout-elasticsearch

配置

  1. 生成 Scout 配置文件(config/scout.php)
$ php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"Copied File [\vendor\laravel\scout\config\scout.php] To [\config\scout.php]Publishing complete.
  1. 指定 Scout 驱动
  • 第一种:在.env文件中指定(倡议)
SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine
  • 第二种:在config/scout.php间接批改默认驱动
'driver' => env('SCOUT_DRIVER', 'algolia')改为'driver' => env('SCOUT_DRIVER', 'Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine')
  1. 指定Elasticsearch服务IP端口

    如果应用docker部署则应用docker0的IP,Linux通过ifconfig查看

    .env中配置

ELASTICSEARCH_HOST=172.17.0.1:9200
  1. 注册服务

config/app.php

'providers' => [    // Other Service Providers    \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class],
  1. 革除配置缓存
$ php artisan config:clear

至此 laravel 曾经接入 Elasticsearch

理论业务中应用

需要

通过博客右上角的搜寻框能够搜寻到与关键词相干的文章,从以下几点匹配

  • 文章内容
  • 文章题目
  • 文章标签

波及到2张 Mysql表 以及字段

  • article

    • title
    • tags
  • article_content

    • content

为文章配置 Elasticsearch 索引

  1. 创立索引配置文件(config/elasticsearch.php)
$ touch config/elasticsearch.php
  1. elasticsearch.php 配置字段映射
<?phpreturn [    'indices' => [        'mappings' => [            'blog-articles' => [                "properties"=>  [                    "content"=>  [                        "type"=>  "text",                        "analyzer"=>  "ik_max_word",                        "search_analyzer"=>  "ik_smart"                    ],                    "tags"=>  [                        "type"=>  "text",                        "analyzer"=>  "ik_max_word",                        "search_analyzer"=>  "ik_smart"                    ],                    "title"=>  [                        "type"=>  "text",                        "analyzer"=>  "ik_max_word",                        "search_analyzer"=>  "ik_smart"                    ]                ]            ]        ]    ],];
  • analyzer:字段文本的分词器

    • search_analyzer:搜索词的分词器
    • 依据具体业务场景抉择(颗粒小占用资源多,个别场景analyzer应用ik_max_word,search_analyzer应用ik_smart):

      • ik_max_word:ik中文分词插件提供,对文本进行最大数量分词
        laravel天下无敌 -> laravel天下无敌,天下,无敌
      • ik_smart: ik中文分词插件提供,对文本进行最小数量分词
    `laravel天下无敌` -> `laravel`,`天下无敌`

配置文章模型

倡议先看一遍 Laravel Scout 应用文档

  1. 引入Laravel Scout

    namespace App\Models\Blog;    use Laravel\Scout\Searchable;class Article extends BlogBaseModel{    use Searchable;}
  2. 指定索引(刚刚配置文件中的elasticsearch.indices.mappings.blog-articles)

    /** * 指定索引
 */public function searchableAs(){    return 'blog-articles';}```
  1. 设置导入索引的数据字段

    /** * 设置导入索引的数据字段
 */public function toSearchableArray(){    return [        'content' => ArticleContent::query()            ->where('article_id',$this->id)            ->value('content'),        'tags'    => implode(',',$this->tags),        'title'   => $this->title    ];}```
  1. 指定 搜寻索引中存储的惟一ID

    /** * 指定 搜寻索引中存储的惟一ID
 */public function getScoutKey(){    return $this->id;}/** * 指定 搜寻索引中存储的惟一ID的键名 * @return string */public function getScoutKeyName(){    return 'id';}```

数据导入

其实是将数据表中的数据通过Elasticsearch导入到Lucene
Elasticsearch 是 Lucene 的封装,提供了 REST API 的操作接口
  • 一键主动导入: php artisan scout:import
  • 导入指定模型: php artisan scout:import ${model}
$ php artisan scout:import "App\Models\Blog\Article"Importing [App\Models\Blog\Article]Switching to the new index5/5 [⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬⚬] 100%[OK] All [App\Models\Blog\Article] records have been imported.

导入失败,常见起因:

  • Unresolvable dependency resolving [Parameter #0 [ <required> integer $retries ]] in class ElasticsearchTransport

    • 解决: 批改配置后,没有革除配置缓存
  • invalid_index_name_exception

    • 解决: searchableAs配置谬误,为索引创立别名后,指定别名

查看索引是否正确

$ curl -XGET http://localhost:9200/blog-articles/_mapping?pretty{  "blog-articles_1598362919" : {    "mappings" : {      "properties" : {        "__class_name" : {          "type" : "text",          "fields" : {            "keyword" : {              "type" : "keyword",              "ignore_above" : 256            }          }        },        "content" : {          "type" : "text",          "analyzer" : "ik_max_word",          "search_analyzer" : "ik_smart"        },        "tags" : {          "type" : "text",          "analyzer" : "ik_max_word",          "search_analyzer" : "ik_smart"        },        "title" : {          "type" : "text",          "analyzer" : "ik_max_word",          "search_analyzer" : "ik_smart"        }      }    }  }}

测试

  1. 创立一个测试命令行
$ php artisan make:command ElasticTest
  1. 代码
<?phpnamespace App\Console\Commands;use App\Models\Blog\Article;use App\Models\Blog\ArticleContent;use Illuminate\Console\Command;use Illuminate\Support\Carbon;class ElasticTest extends Command{    /**     * The name and signature of the console command.     *     * @var string     */    protected $signature = 'elasticsearch {query}';    /**     * The console command description.     *     * @var string     */    protected $description = 'elasticsearch test';    /**     * Create a new command instance.     *     * @return void     */    public function __construct()    {        parent::__construct();    }    /**     * Execute the console command.     *     * @return mixed     */    public function handle()    {        //        $startTime = Carbon::now()->getPreciseTimestamp(3);        $articles = Article::search($this->argument('query'))->get()->toArray();        $userTime = Carbon::now()->getPreciseTimestamp(3) - $startTime;        echo "耗时(毫秒):{$userTime} \n";                //content在另外一张表中,不便察看测试 这里输入        if(!empty($articles)) {            foreach($articles as &$article) {                $article = ArticleContent::query()->where('article_id',$article['id'])->value('content');            }        }        var_dump($articles);    }}
  1. 测试
$ php artisan elasticsearch 周杰伦

  1. 高亮显示片段

高亮显示须要自定义查问,外围代码

//ONGR\ElasticsearchDSL\Highlight\Highlight ArticleModel::search($query,function($client,$body) {            $higlight = new Highlight();            $higlight->addField('content',['type' => 'plain']);            $higlight->addField('title');            $higlight->addField('tags');            $body->addHighlight($higlight);            $body->setSource(['title','tags']);            return $client->search(['index' => (new ArticleModel())->searchableAs(), 'body' => $body->toArray()]);        })->raw();

自定义查问可参考以两个包灵便开发

  • $client elasticsearch/elasticsearch package
  • $body ongr/elasticsearch-dsl package