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提交表单时判断 if($_POST[submit])与 if(isset($_POST[submit])) 的区别
Feb 08 PHP
基于php 随机数的深入理解
Jun 05 PHP
深入Memcache的Session数据的多服务器共享详解
Jun 13 PHP
php一次性删除前台checkbox多选内容的方法
Sep 22 PHP
php中多维数组按指定value排序的实现代码
Aug 19 PHP
php实现的ping端口函数实例
Nov 12 PHP
Zend Framework入门之环境配置及第一个Hello World示例(附demo源码下载)
Mar 21 PHP
php如何控制用户对图片的访问 PHP禁止图片盗链
Mar 25 PHP
Yii实现文章列表置顶功能示例
Oct 18 PHP
PHP 实现浏览记录并按日期分组
May 11 PHP
Laravel5.1框架注册中间件的三种场景详解
Jul 09 PHP
如何用PHP实现分布算法之一致性哈希算法
May 26 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中强制下载文件的代码(解决了IE下中文文件名乱码问题)
2011/05/09 PHP
php实现获取文件mime类型的方法
2015/02/11 PHP
php实现的pdo公共类定义与用法示例
2017/07/19 PHP
PDO::_construct讲解
2019/01/27 PHP
基于jQuery的Spin Button自定义文本框数值自增或自减
2010/07/17 Javascript
JS字符串函数扩展代码
2011/09/13 Javascript
jquery简单实现幻灯片的方法
2015/08/03 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
简单实现js间歇或无缝滚动效果
2016/06/29 Javascript
浅谈pc端rem字体设置的问题
2017/08/03 Javascript
关于vue中的ajax请求和axios包问题
2018/04/19 Javascript
jQuery仿移动端支付宝键盘的实现代码
2018/08/15 jQuery
mpvue+vant app搭建微信小程序的方法步骤
2019/02/11 Javascript
深入探讨JavaScript的最基本部分之执行上下文
2019/02/12 Javascript
VSCode搭建Vue项目的方法
2020/04/30 Javascript
Vue 请求传公共参数的操作
2020/07/31 Javascript
Win7上搭建Cocos2d-x 3.1.1开发环境
2014/07/03 Python
树莓派用python中的OpenCV输出USB摄像头画面
2019/06/22 Python
解决python执行不输出系统命令弹框的问题
2019/06/24 Python
Python批量查询关键词微信指数实例方法
2019/06/27 Python
Python3 main函数使用sys.argv传入多个参数的实现
2019/12/25 Python
使用numpngw和matplotlib生成png动画的示例代码
2021/01/24 Python
canvas 橡皮筋式线条绘图应用方法
2019/02/13 HTML / CSS
使用canvas一步步实现图片打码功能的方法
2019/06/17 HTML / CSS
Chantelle仙黛尔内衣美国官网:法国第一品牌内衣
2018/07/26 全球购物
伦敦最受欢迎的蛋糕店:Konditor & Cook
2019/11/01 全球购物
JDBC操作数据库的基本流程是什么
2014/10/28 面试题
省三好学生申请材料
2014/01/22 职场文书
工作表现自我评价
2014/02/08 职场文书
2014年父亲节活动方案
2014/03/06 职场文书
工地安全生产标语
2014/06/06 职场文书
一份教室追逐打闹的检讨书
2014/09/27 职场文书
公安局班子个人对照检查材料思想汇报
2014/10/09 职场文书
2014年服务员个人工作总结
2014/12/23 职场文书
在职证明范本
2015/06/15 职场文书
好员工观后感
2015/06/17 职场文书