Laravel + Elasticsearch 实现中文搜索的方法


Posted in PHP onFebruary 02, 2020

Laravel + Elasticsearch 实现中文搜索的方法

Elasticsearch

Elasticsearch 是一个基于 Apache Lucene(TM) 的开源搜索引擎,无论在开源还是专有领域,Lucene可 以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

但是,Lucene 只是一个库。想要发挥其强大的作用,你需使用 Java 并要将其集成到你的应用中。Lucene 非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。

Elasticsearch 也是使用 Java 编写并使用 Lucene 来建立索引并实现搜索功能,但是它的目的是通过简单连贯的 RESTful API 让全文搜索变得简单并隐藏 Lucene 的复杂性。

不过,Elasticsearch 不仅仅是 Lucene 和全文搜索引擎,它还提供:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 实时分析的分布式搜索引擎
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

而且,所有的这些功能被集成到一台服务器,你的应用可以通过简单的 RESTful API、各种语言的客户端甚至命令行与之交互。上手 Elasticsearch 非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。

Elasticsearch 在 Apache 2 license 下许可使用,可以免费下载、使用和修改。

ElasticSearch 安装

在 Laradock 中已经集成了 ElasticSearch。我们可以直接使用:

docker-compose up -d elasticsearch

如果需要安装插件,执行命令:

docker-compose exec elasticsearch /usr/share/elasticsearch/bin/elasticsearch-plugin install {plugin-name}

// 重启容器
docker-compose restart elasticsearch

注:

The vm.max_map_count kernel setting must be set to at least 262144 for production use.

由于我是 centos 7 环境,直接设置在系统设置:
sysctl -w vm.max_map_count=262144

默认用户名和密码:「elastic」、「changeme」,端口号:9200

Laravel + Elasticsearch 实现中文搜索的方法

ElasticHQ

Laravel + Elasticsearch 实现中文搜索的方法

ElasticHQ is an open source application that offers a simplified interface for managing and monitoring Elasticsearch clusters.

Management and Monitoring for Elasticsearch.

http://www.elastichq.org/

  • Real-Time Monitoring
  • Full Cluster Management
  • Full Cluster Monitoring
  • Elasticsearch Version Agnostic
  • Easy Install - Always On
  • Works with X-Pack

Laravel + Elasticsearch 实现中文搜索的方法

输入我们的 Elasticsearch Host,即可进入后台。

Laravel + Elasticsearch 实现中文搜索的方法

默认的创建了:

一个集群 cluster:laradock-cluster
一个节点 node:laradock-node
一个索引 index:.elastichq

IK 分词器安装

ElasticSearch 主要是用于自己 blog 或者公众号文章的搜索使用,所以需要选择一个中文分词器配合使用,这里刚开始推荐使用 IK 分词器,下面开始安装对应 ElasticSearch版本 (7.5.1) 一致的插件:

https://github.com/medcl/elasticsearch-analysis-ik/releases

Laravel + Elasticsearch 实现中文搜索的方法

// 安装插件
docker-compose exec elasticsearch /usr/share/elasticsearch/bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.1/elasticsearch-analysis-ik-7.5.1.zip

Laravel + Elasticsearch 实现中文搜索的方法

注:可以将 zip 文件先下载回来,然后再安装,速度会快些。

检验分词效果

根据 Elasticsearch API 测试,分词的效果达到了:

~ curl -X POST "http://your_host/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
 "analyzer": "ik_max_word",
 "text":   "我是中国人"
}
'

{
 "tokens" : [
  {
   "token" : "我",
   "start_offset" : 0,
   "end_offset" : 1,
   "type" : "CN_CHAR",
   "position" : 0
  },
  {
   "token" : "是",
   "start_offset" : 1,
   "end_offset" : 2,
   "type" : "CN_CHAR",
   "position" : 1
  },
  {
   "token" : "中国人",
   "start_offset" : 2,
   "end_offset" : 5,
   "type" : "CN_WORD",
   "position" : 2
  },
  {
   "token" : "中国",
   "start_offset" : 2,
   "end_offset" : 4,
   "type" : "CN_WORD",
   "position" : 3
  },
  {
   "token" : "国人",
   "start_offset" : 3,
   "end_offset" : 5,
   "type" : "CN_WORD",
   "position" : 4
  }
 ]
}

结合 Laravel

虽然 Elasticsearch 官方提供了对应的 PHP 版本的插件,但我们还是希望和 Laravel 结合的更紧密些,所以这里选择和 Scout 结合使用,具体用到了 tamayo/laravel-scout-elastic 插件。

composer require tamayo/laravel-scout-elastic
 
composer require laravel/scout
 
php artisan vendor:publish

选择:Laravel\Scout\ScoutServiceProvider

Laravel + Elasticsearch 实现中文搜索的方法

修改驱动为 elasticsearch

'driver' => env('SCOUT_DRIVER', 'elasticsearch'),

创建索引

创建索引有几种方法,其中可以使用 Ela 可视化工具 ElasticHQ 直接创建。

Laravel + Elasticsearch 实现中文搜索的方法

Laravel + Elasticsearch 实现中文搜索的方法

接下来我们需要更新这个索引,补充 Mappings 这部分,可以用 Postman。

Laravel + Elasticsearch 实现中文搜索的方法

另一种方法是用 Laravel 自带的 Artisan 命令行功能。

这里我们推荐使用 Artisan 命令行。
php artisan make:command ESOpenCommand

根据官网提示,我们可以在 ESOpenCommand 上向 Elasticsearch 服务器发送 PUT 请求,这里借助 Elasticsearch 提供的 PHP 插件,在我们使用 tamayo/laravel-scout-elastic 插件时,已经安装了 Elasticsearch PHP 插件:

Laravel + Elasticsearch 实现中文搜索的方法

下面就可以借助插件,创建我们的 Index,直接看代码:

public function handle()
  {
  $host = config('scout.elasticsearch.hosts');
  $index = config('scout.elasticsearch.index');
  $client = ClientBuilder::create()->setHosts($host)->build();

  if ($client->indices()->exists(['index' => $index])) {
    $this->warn("Index {$index} exists, deleting...");
    $client->indices()->delete(['index' => $index]);
  }

  $this->info("Creating index: {$index}");

  return $client->indices()->create([
    'index' => $index,
    'body' => [
      'settings' => [
        'number_of_shards' => 1,
        'number_of_replicas' => 0
      ],
      'mappings' => [
        '_source' => [
          'enabled' => true
        ],
        'properties' => [
          'id' => [
            'type' => 'long'
          ],
          'title' => [
            'type' => 'text',
            'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart'
          ],
          'subtitle' => [
            'type' => 'text',
            'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart'
          ],
          'content' => [
            'type' => 'text',
            'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart'
          ]
        ],
      ]
    ]
  ]);
}

Laravel + Elasticsearch 实现中文搜索的方法

好了,我们执行 Kibana 看到我们已经创建好了 Index:

Laravel + Elasticsearch 实现中文搜索的方法

注 Kibana 本地 Docker 安装:

后续会重点说明 Kibana 如何使用

docker run -d --name kibana -e ELASTICSEARCH_HOSTS=http://elasticsearch_host -p 5601:5601 -e SERVER_NAME=ki.test kibana:7.5.2

为了验证 Index 是否可用,可以插入一条数据看看:

curl -XPOST your_host/coding01_open/_create/1 -H 'Content-Type:application/json' -d'
{"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}

Laravel + Elasticsearch 实现中文搜索的方法

可以通过浏览器看看对应的数据:

Laravel + Elasticsearch 实现中文搜索的方法

有了 Index,下一步我们就可以结合 Laravel,导入、更新、查询等操作了。

Laravel Model 使用

Laravel 框架已经为我们推荐使用 Scout 全文搜索,我们只需要在 Article Model 加上官方所说的内容即可,很简单,推荐大家看 Scout 使用文档:https://learnku.com/docs/laravel/6.x/scout/5191,下面直接上代码:

<?php

namespace App;

use App\Tools\Markdowner;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;

class Article extends Model
{
  use Searchable;

  protected $connection = 'blog';
  protected $table = 'articles';
  use SoftDeletes;

  /**
   * The attributes that should be mutated to dates.
   *
   * @var array
   */
  protected $dates = ['published_at', 'created_at', 'deleted_at'];

  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = [
    'user_id',
    'last_user_id',
    'category_id',
    'title',
    'subtitle',
    'slug',
    'page_image',
    'content',
    'meta_description',
    'is_draft',
    'is_original',
    'published_at',
    'wechat_url',
  ];

  protected $casts = [
    'content' => 'array'
  ];

  /**
   * Set the content attribute.
   *
   * @param $value
   */
  public function setContentAttribute($value)
  {
    $data = [
      'raw' => $value,
      'html' => (new Markdowner)->convertMarkdownToHtml($value)
    ];

    $this->attributes['content'] = json_encode($data);
  }

  /**
   * 获取模型的可搜索数据
   *
   * @return array
   */
  public function toSearchableArray()
  {
    $data = [
      'id' => $this->id,
      'title' => $this->title,
      'subtitle' => $this->subtitle,
      'content' => $this->content['html']
    ];

    return $data;
  }

  public function searchableAs()
  {
    return '_doc';
  }
}

Scout 提供了 Artisan 命令 import 用来导入所有已存在的记录到搜索索引中。

php artisan scout:import "App\Article"

Laravel + Elasticsearch 实现中文搜索的方法

看看 Kibana,已存入 12 条数据,和数据库条数吻合。

Laravel + Elasticsearch 实现中文搜索的方法

有了数据,我们可以测试看看能不能查询到数据。

还是一样的,创建一个命令:

class ElasearchCommand extends Command
{
  /**
   * The name and signature of the console command.
   *
   * @var string
   */
  protected $signature = 'command:search {query}';

  /**
   * The console command description.
   *
   * @var string
   */
  protected $description = 'Command description';

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

  /**
   * Execute the console command.
   *
   * @return mixed
   */
  public function handle()
  {
    $article = Article::search($this->argument('query'))->first();
    $this->info($article->title);
  }
}

Laravel + Elasticsearch 实现中文搜索的方法

这是我的 titles,我随便输入一个关键字:「清单」,看是否能搜到。

Laravel + Elasticsearch 实现中文搜索的方法

总结

整体完成了:

  • Elasticsearch 安装;
  • Elasticsearch IK 分词器插件安装;
  • Elasticsearch 可视化工具 ElasticHQ 和 Kibana 的安装和简单使用;
  • Scout 的使用;
  • Elasticsearch 和 Scout 结合使用。

接下来就要将更多的内容存入 Elasticsearch 中,为自己的 blog、公众号、自动化搜索等场景提供全文搜索。

参考

推荐一个命令行应用开发工具——Laravel Zero

Artisan 命令行 https://learnku.com/docs/laravel/6.x/artisan/5158

Scout 全文搜索 https://learnku.com/docs/laravel/6.x/scout/5191

How to integrate Elasticsearch in your Laravel App ? 2019 edition https://madewithlove.be/how-to-integrate-elasticsearch-in-your-laravel-app-2019-edition/

Kibana Guide https://www.elastic.co/guide/en/kibana/index.html

elasticsearch php-api [https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP面向对象的使用教程 简单数据库连接
Nov 25 PHP
PHP实现Socket服务器的代码
Apr 03 PHP
php 函数使用方法与函数定义方法
May 09 PHP
PHP中用接口、抽象类、普通基类实现“面向接口编程”与“耦合方法”简述
Mar 23 PHP
php学习笔记 面向对象中[接口]与[多态性]的应用
Jun 16 PHP
php设计模式之观察者模式的应用详解
May 21 PHP
PHP CURL获取cookies模拟登录的方法
Nov 04 PHP
ThinkPHP3.1新特性之动态设置自动完成和自动验证示例
Jun 19 PHP
详解php中反射的应用
Mar 15 PHP
基于thinkphp6.0的success、error实现方法
Nov 05 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
Nov 14 PHP
PHP过滤器 filter_has_var() 函数用法实例分析
Apr 23 PHP
php封装的page分页类完整实例代码
Feb 01 #PHP
PHP实现简单的协程任务调度demo示例
Feb 01 #PHP
PHP设计模式之组合模式定义与应用示例
Feb 01 #PHP
php实现的简单多进程服务器类完整示例
Feb 01 #PHP
laravel 框架执行流程与原理简单分析
Feb 01 #PHP
laravel框架学习笔记之组件化开发实现方法
Feb 01 #PHP
php正则表达式使用方法整理集合
Jan 31 #PHP
You might like
PHP语法速查表
2006/12/06 PHP
php网站判断用户是否是手机访问的方法
2013/11/01 PHP
PHP图片处理之使用imagecopyresampled函数裁剪图片例子
2014/11/19 PHP
php实现mysql数据库分表分段备份
2015/06/18 PHP
php下载远程大文件(获取远程文件大小)的实例
2017/06/17 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
2017/11/16 PHP
获取css样式表内样式的js函数currentStyle(IE),defaultView(FF)
2011/02/14 Javascript
AngularJS中取消对HTML片段转义的方法例子
2015/01/04 Javascript
jQuery基于图层模仿五星星评价功能的方法
2015/05/07 Javascript
原生JS取代一些JQuery方法的简单实现
2016/09/20 Javascript
Bootstrap的class样式小结
2016/12/01 Javascript
深入探究node之Transform
2017/07/20 Javascript
利用Javascript获取选择文本所在的句子详解
2017/12/03 Javascript
JS计算距当前时间的时间差实例
2017/12/29 Javascript
Vue-cli配置打包文件本地使用的教程图解
2018/08/02 Javascript
vue2.0$nextTick监听数据渲染完成之后的回调函数方法
2018/09/11 Javascript
[39:08]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第一场 12.12
2020/12/16 DOTA
Python求两个list的差集、交集与并集的方法
2014/11/01 Python
Python编程中装饰器的使用示例解析
2016/06/20 Python
如何用python整理附件
2018/05/13 Python
python 字典中取值的两种方法小结
2018/08/02 Python
Python面向对象之类的内置attr属性示例
2018/12/14 Python
使用Python做定时任务及时了解互联网动态
2019/05/15 Python
Python安装及Pycharm安装使用教程图解
2019/09/20 Python
python 队列基本定义与使用方法【初始化、赋值、判断等】
2019/10/24 Python
使用python实现画AR模型时序图
2019/11/20 Python
python 实现二维列表转置
2019/12/02 Python
python 使用cx-freeze打包程序的实现
2020/03/14 Python
利用纯CSS3实现文字向右循环闪过效果实例(可用于移动端)
2017/06/15 HTML / CSS
马来西亚最好的婴儿商店:Motherhood
2017/09/14 全球购物
Oracle性能调优原则
2012/05/03 面试题
护士自我鉴定怎么写
2014/02/07 职场文书
《小白兔和小灰兔》教学反思
2014/02/18 职场文书
社区优秀志愿者先进事迹
2014/05/09 职场文书
三孔导游词
2015/02/05 职场文书
Java Socket实现多人聊天系统
2021/07/15 Java/Android