调用博主最近登录时间
生活中的HYGGE
Laravel+Scout+Elasticsearch实现中文分词搜索功能
PHP

Laravel+Scout+Elasticsearch实现中文分词搜索功能

hygge
2023-01-18 / 0 评论 / 14 阅读 / 正在检测是否收录...

一、准备工作

1.配置机器ssh连接

sudo apt update
sudo apt install openssh-server # ssh

二、Docker安装ElasticSearch

2.1 安装说明

在平时工作的时候,开发环境大多数会安装单机ElasticSearch,但生产环境基本会安装ElasticSearch集群版。不过中文搜索,会实现分词器集成,可以采用IK分词器。ElasticSearch采用Kibana实现数据可视化分析也是当前主流,所以我们除了安装ElasticSearchIK分词器外,还需要安装Kibana

安装实践:

1:ElasticSearch单机安装

2:IK分词器安装

3:Kibana安装

2.2 Docker安装ElasticSearch

当前ElasticSearch已经到了8.0,新版本都有很多新特性,性能和功能都有大幅提升,我们建议使用较高版本,这里将采用8.6.0版本。

2.2.1 网络创建

高版本安装Kibana的时候需要和ElasticSearch在同一网段内,所以采用docker安装首先要确认网段,为了方便操作,我们直接创建一个网络,创建脚本如下:

sudo docker network create elastic-series

ld11zb52.png

2.2.2 ElasticSearch安装

安装ElasticSearch脚本如下:

sudo docker run -d \
    --name elasticsearch \
    -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
    -e "discovery.type=single-node" \
    -v es-data:/usr/share/elasticsearch/data \
    -v es-plugins:/usr/share/elasticsearch/plugins \
    --privileged \
    --network elastic-series \
    -p 9200:9200 \
    -p 9300:9300 \
elasticsearch:8.6.0

命令说明:

  • -e "cluster.name=es-docker-cluster":设置集群名称
  • -e "http.host=0.0.0.0":监听的地址,可以外网访问
  • -e "ES_JAVA_OPTS=-Xms512m -Xmx512m":内存大小
  • -e "discovery.type=single-node":非集群模式
  • -v es-data:/usr/share/elasticsearch/data:挂载逻辑卷,绑定elasticsearch的数据目录
  • -v es-logs:/usr/share/elasticsearch/logs:挂载逻辑卷,绑定elasticsearch的日志目录
  • -v es-plugins:/usr/share/elasticsearch/plugins:挂载逻辑卷,绑定elasticsearch的插件目录
  • --privileged:授予逻辑卷访问权
  • --network elastic-series :加入一个名为elastic-series的网络中
  • -p 9200:9200:端口映射配置

Docker安装ElasticSearch下载可能会比较慢,需要耐心等待,效果如下:

ld11zkrk.png

安装完成后,在浏览器中输入:http://192.168.211.128:9200/即可看到elasticsearch的响应结果:

ld11zs1k.png

You can Generate a new password using

/usr/share/elasticsearch/elasticsearch-setup-passwords auto/interactive

interactive is where you will have to enter password for all user.

auto will just print passwords on the shell.

else

You can turn off x-pack security in elasticsearch.yml

2.2.2.1 关闭安全验证

1.进入容器内部

sudo docker exec -it -u root <container> bash

2.安装Vim,为编辑文件做准备

apt-get update
apt-get install vim

3.编辑config/elasticsearch.yml

# 追加
xpack.security.enabled: false

4.退出并重启容器

exit
sudo docker restart <container>

刷新页面,得到正常响应

ld12025h.png

 3 安装Kibana

我们可以基于Http请求操作ElasticSearch,但基于Http操作比较麻烦,我们可以采用Kibana实现可视化操作。

2.2.2.2 设置密码

详见引用第九条

三、Docker安装Kibana

3.1 Kibana介绍

ld1208lw.png

Kibana 是一个免费且开放的用户界面,能够让您对 Elasticsearch 数据进行可视化,并让您在 Elastic Stack 中进行导航。您可以进行各种操作,从跟踪查询负载,到理解请求如何流经您的整个应用,都能轻松完成。

Kibana 让您能够自由地选择如何呈现自己的数据。不过借助 Kibana 的交互式可视化,您可以先从一个问题出发,看看能够从中发现些什么。

可视化界面如下:

ld120f2g.png

3.2 Kibana安装

使用Docker安装Kibana非常简单,只需要执行如下命令即可,但是执行命令需要注意Kibana操作的ElasticSearch地址,因为Kibana是需要连接ElasticSearch进行操作的,命令如下:

sudo docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://192.168.211.128:9200 \
--network elastic-series \
-p 5601:5601  \
kibana:8.6.0

命令说明:

  • --network elastic-series :加入一个名为elastic-series的网络中,与elasticsearch在同一个网络中
  • -e ELASTICSEARCH_HOSTS=http://192.168.211.128:9200":设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch,也可以写IP地址实现访问。
  • -p 5601:5601:端口映射配置

安装的时候如果没有镜像,会下载镜像,效果如下:

ld120me5.png

kibana安装会比较耗时间,也需要耐心等待下载安装完成,如果想实时知道服务安装运行的状态,可以通过查看日志实现,查看日志如下:

docker logs -f kibana

日志中如果出现了http://0.0.0.0:5601即可访问Kibana后台服务,日志如下:

ld120stp.png

访问http://192.168.211.128:5601效果如下:

ld120zn3.png

可以点击Add integrations,添加示例数据,如下图,随意选一个即可,不选其实也是可以的。

ld1215u2.png

3.3 Kibana中文配置

我们发现Kibana是英文面板,看起来不是很方便,但Kibana是支持中文配置,所以我们可以把Kibana配置成中文版,便于我们操作。

切换中文操作如下:

#进入容器
docker exec -it kibana /bin/bash

#进入配置文件目录
cd /usr/share/kibana/config

#编辑文件kibana.yml
vi kibana.yml

#在最后一行添加如下配置
i18n.locale: zh-CN

#保存退出
exit

#并重启容器
docker restart kibana

 等待Kibana容器启动,再次访问http://192.168.211.128:5601/效果如下:

ld121fwq.png

四、IK分词器安装

我们打开Kibana,点击开发工具,操作如下:

ld121o3s.png

输入如下操作,用于查询分词:

ld121tfv.png

上图测试代码如下:

GET _analyze
{
  "analyzer": "standard",
  "text": "过去无可挽回,未来可以改变"
}

表示使用standard过去无可挽回,未来可以改变进行分词。

分词:提取一句话或者一篇文章中的词语。

我们在使用ElasticSearch的时候,默认用standard分词器,但standard分词器使用的是按空格分词,这种分词操作方法不符合中文分词标准,我们需要额外安装中文分词器。

4.1 IK分词器介绍

IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始, IKAnalyzer已经推出了多个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。IK Analyzer则发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。

ElasticSearch内核其实就是基于Lucene,所以我们可以直接在ElasticSearch中集成IK分词器,IK分词器集成ElasticSearch下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases

ld1221ti.png

4.2 IK分词器配置

下载安装包elasticsearch-analysis-ik-8.6.0.zip后,并解压,目录如下:

ld1228k2.png

我们只需要将上面ik拷贝到ElasticSearchplugins目录中即可,但由于当前服务采用的是docker安装,所以需要将文件拷贝到docker容器的plugins目录才行。

操作如下:

#将ik文件夹拷贝到elasticsearch容器中
docker cp ik elasticsearch:/usr/share/elasticsearch/plugins

#重启容器
docker restart elasticsearch

操作效果如下:

ld122f2l.png

4.3 分词测试

IK分词器包含两种模式:

  • ik_smart:最少切分
  • ik_max_word:最细切分

前面使用默认的standard分词器,对中文分词非常难用,安装IK分词器后,我们可以使用IK分词器测试,测试代码如下:

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "过去无可挽回,未来可以改变"
}

测试效果如下:

ld122loe.png

我们可以发现对中文的分词效果是比较不错的,但也存在一些不足,比如无可挽回我们希望它是一个词,而可挽回我们希望它不被识别一个词,又该如何实现呢?

自定义词典参考引用中的第2个链接

五、Laravel集成

使用的第三方包matchish/laravel-scout-elasticsearch:https://github.com/matchish/laravel-scout-elasticsearch

名称版本
php^8.0.2
laravel/framework^9.19
matchish/laravel-scout-elasticsearch^6.0

5.1 介绍

Laravel Scout 为 Eloquent 模型 的全文搜索提供了一个简单的基于驱动程序的解决方案,通过使用模型观察者,Scout 将自动同步 Eloquent 记录的搜索索引。

目前,Scout 附带 Algolia、MeiliSearch 和 MySQL / PostgreSQL (database) 驱动程序。此外,Scout 包括一个「collection」驱动程序,该驱动程序专为本地开发使用而设计,不需要任何外部依赖项或第三方服务。此外,编写自定义驱动程序很简单,你可以使用自己的搜索实现自由扩展 Scout。

由于没有自带Elasticsearch的驱动,所以需要第三方包

5.1 安装包和配置

1.引入包

composer require matchish/laravel-scout-elasticsearch

2.env设置环境变量

SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine
ELASTICSEARCH_HOST=192.168.211.128:9200

3.config/app.php中配置provider

'providers' => [
    // Other Service Providers

    \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class
],

4.发布配置文件

php artisan vendor:publish --tag config

会新增config/elasticsearch.php文件

5.2 更新模型

1.更新模型

<?php

namespace App\Models;

use App\Trait\DefaultDatetimeFormat;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;


class Video extends Model
{
    use DefaultDatetimeFormat, Searchable;


    protected $fillable = ['img', 'title', 'innerVideoHref', 'innerHref', 'viewNumber', 'likeNumber', 'helpInfo', 'type'];

    /**
     * Get the indexable data array for the model.
     * 我想只根据title来分词检索
     * @return array
     */
    public function toSearchableArray()
    {
        return $this->only(['title']);
    }

    /**
     * Get the index name for the model.
     * 指定索引的名称
     * @return string
     */
    public function searchableAs()
    {
        return 'videos_index';
    }

    /**
     * 指定 搜索索引中存储的唯一ID
     * @return mixed
     */
    public function getScoutKey()
    {
        return $this->id;
    }

    /**
     * 指定 搜索索引中存储的唯一ID的键名
     * @return string
     */
    public function getScoutKeyName()
    {
        return 'id';
    }
}

2.修改config/elasticsearch.php

<?php

return [
    'host' => env('ELASTICSEARCH_HOST','192.168.211.128:9200'),
    'indices' => [
        'mappings' => [
            'default' => [
                'properties' => [
                    'id' => [
                        'type' => 'keyword',
                    ],
                ],
            ],
            // 与上一步的索引名称对应
            'videos_index' => [
                'properties' => [
                    'title' => [
                        'type' => 'text',
                        'analyzer' => 'ik_max_word',
                        'search_analyzer' => 'ik_max_word',
                    ],
                ],
            ],
        ],
        'settings' => [
            'default' => [
                'number_of_shards' => 1,
                'number_of_replicas' => 0,
            ],
        ],
    ],
];

3.索引的批量导入

php artisan scout:import

ld12322x.png

ld12369f.png

5.3 使用

场景:根据当前播放的视频名称,检索出来十个相关的视频作为推荐

public function play($type, $id)
{
    // 直接根据类型和视频ID进行查询
    $video = Video::where('type', $type)->where('id', $id)->first();
    $videoSeries = Video::search($video->title)->take(10)->get();
    dd($videoSeries);
}

ld123cfc.png

六、遇到的问题

6.1 Kibana 服务器尚未准备就绪。

在服务器上部署时,访问Kibana出现了

ld123iyl.png

查看日志

docker logs kibana
[2023-01-18T02:05:30.467+00:00][ERROR][elasticsearch-service] Unable to retrieve version information from Elasticsearch nodes. connect ECONNREFUSED 127.0.0.1:9200

原因是创建容器时填写的

sudo docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://127.0.0.1:9200 \
-p 5601:5601  \
kibana:8.6.0

这里不可以使用127.0.0.1需要使用私有IP

ld123p9l.png

重新创建后即可正常访问

6.2 无法访问

在虚拟机上部署时按照步骤并开放端口是可以访问9200和5601端口

在服务器上按照 创建网络 -> 创建elasticsearch、kibana容器设置网络 的步骤走下来 始终访问不了对应的端口

不清楚原因,于是去掉了创建容器时的网络配置

引用

1.如何在 Ubuntu 20.04 启用 SSH :https://zhuanlan.zhihu.com/p/145763789

2.你必须会的Docker安装ElasticSearch教程:https://juejin.cn/post/7074115690340286472

3.Install Kibana with Docker:https://www.elastic.co/guide/en/kibana/current/docker.html

4.Elasticsearch_Installation_asking for username and password:https://stackoverflow.com/questions/71269878/elasticsearch-installation-asking-for-username-and-password

5.Releases · medcl/elasticsearch-analysis-ik (github.com):https://github.com/medcl/elasticsearch-analysis-ik/releases

6.matchish/laravel-scout-elasticsearch: Search among multiple models with ElasticSearch and Laravel Scout (github.com):https://github.com/matchish/laravel-scout-elasticsearch

7.只需五步 集成新版 Elasticsearch7.9 中文搜索 到你的 Laravel7 项目:https://juejin.cn/post/6865188575114330126

8.php Laravel 使用elasticsearch+ik中文分词器搭建搜索引擎:https://blog.csdn.net/weixin_42701376/article/details/126782529?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-2-126782529-blog-109466440.pc_relevant_multi_platform_whitelistv4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-2-126782529-blog-109466440.pc_relevant_multi_platform_whitelistv4&utm_relevant_index=3

9.docker中设置elasticsearch、kibana用户名密码、修改密码:https://blog.csdn.net/IT_road_qxc/article/details/121858843

0

评论 (0)

取消