关于es的详细介绍以及安装包编译安装的方式,可以看之前的文章:安装Elasticsearch搜索引擎
这次换个花样,使用docker(这里不解释docker是什么了,不了解的自行百度)来安装,直接开搞,操作如下
安装docker
# 安装
yum install -y docker
# 查看版本信息
docker version
# 修改docker的镜像源
vim /etc/docker/daemon.json
{
    "registry-mirrors": ["https://ftnejmh3.mirror.aliyuncs.com"]
}
 # 启动docker
systemctl start docker
# 停止docker
systemctl stop docker
# 查看docker状态
systemctl status docker
# 重新启动docker
systemctl restart docker如果docker没有命令自动补全功能,可以安装如下
yum -y install bash-completion source /usr/share/bash-completion/bash_completion
拉取es镜像(文件有点大,需要必定时间)
docker pull elasticsearch:7.12.1
在宿主机创建和容器内共享的目录
# 存放配置文件目录 mkdir -p /docker/es/conf # 存放数据目录 mkdir -p /docker/es/data # 存放日志目录 mkdir -p /docker/es/logs # 存放插件目录 mkdir -p /docker/es/plugins # 创建好目录后为了防止下边创建容器报错,给宿主机的这个es目录赋个读写权限 chmod -R 777 /docker/es/
创建es配置文件(参数意思不解释,上方提到的文章内有解释)
vi /docker/es/conf/elasticsearch.yml
cluster.name: my-application node.name: node-1 path.data: /usr/share/elasticsearch/data path.logs: /usr/share/elasticsearch/logs network.host: 0.0.0.0 http.port: 9200 cluster.initial_master_nodes: ["node-1"]
构建容器(构建很快,但是容器内es的启动速度很慢,构建完先耐心等待一下)
docker run -p 9200:9200 -d --name es -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -v /docker/es/conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /docker/es/data:/usr/share/elasticsearch/data -v /docker/es/plugins:/usr/share/elasticsearch/plugins -v /docker/es/logs:/usr/share/elasticsearch/logs --privileged=true elasticsearch:7.12.1
异常处理
好事多磨,一般这里都会出点小问题,启动失败使用 docker logs es | grep error 命令来查看报错信息。我遇到的有异常:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决方案:
1. 修改配置sysctl.conf: vi /etc/sysctl.conf 2. 在尾行添加以下内容: vm.max_map_count=655300 3. 刷新配置: sysctl -p
测试,在浏览器中访问服务地址+9200的端口,可以显示以下信息证明安装成功
PS:如果打不开,请检查es是否正确启动以及9200端口是否开放
{
  "name" : "node-1",
  "cluster_name" : "my-application",
  "cluster_uuid" : "b-ovHR-GRvunpTmWOfoLKw",
  "version" : {
    "number" : "7.12.1",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "3186837139b9c6b6d23c3200870651f10d3343b7",
    "build_date" : "2021-04-20T20:56:39.040728659Z",
    "build_snapshot" : false,
    "lucene_version" : "8.8.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}拉取镜像
docker pull kibana:7.12.1
在宿主机创建和容器内共享的目录
mkdir -p /docker/kibana/conf
创建配置文件
vi /docker/kibana/conf/kibana.yml
server.name: kibana server.host: "0.0.0.0" elasticsearch.hosts: ["http://你的es地址:9200"] xpack.monitoring.ui.container.elasticsearch.enabled: true
构建容器
docker run -p 5601:5601 -d --name kibana -v /docker/kibana/conf/kibana.yml:/usr/share/kibana/config/kibana.yml --privileged=true kibana:7.12.1
访问测试:http://服务ip:5601
下载安装包
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.12.1
解压安装包
PS:这个安装包解压完文件是分散的,所以需要在 plugins 目录下先建好放置文件的目录
mkdir /docker/es/plugins/ik mv elasticsearch-analysis-ik-7.12.1.zip /docker/es/plugins/ik/ cd /docker/es/plugins/ik unzip elasticsearch-analysis-ik-7.12.1.zip rm -rf elasticsearch-analysis-ik-7.12.1.zip
重启es容器
docker restart es
注意事项
安装es的ik分词器可能会导致es内存溢出,可以在es配置中增加内存限制
indices.fielddata.cache.size: 50%
安装composer组件包
composer require elasticsearch/elasticsearch "7.12.x" --ignore-platform-reqs
配置
# 在 .env 文件中加入es的地址配置,如果是集群存在多个地址则用 ,隔开 ES_HOSTS=172.17.0.8,172.17.0.9,172.17.0.10 # 在 config/database.php 配置文件中加入 # 端口不用加,默认就是9200,但是如果改了端口那这里就要加入端口的配置 elasticsearch => [ hosts => explode( , , env( ES_HOSTS )), ]
初始化 Elasticsearch 对象,并注入到 laravel 容器中
在 App/Providers/AppServiceProvider.php 文件的register方法中定义服务对象
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
use ElasticsearchClientBuilder as ESClientBuilder;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // 注册一个名为 es 的单例
        $this->app->singleton( es , function () {
            // 从配置文件读取 Elasticsearch 服务器列表
            $builder =  ESClientBuilder::create()->setHosts(config( database.elasticsearch.hosts ));
            // 如果是开发环境
            if (app()->environment() ===  local ){
                // 配置日志,Elasticsearch 的请求和返回数据将打印到日志文件中,便于调试
                $builder->setLogger(app( log )->driver());
            }
            
            return $builder->build();
        });
    }
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}然后就可以在项目中使用 app( es ) 的方式来调用es了
测试是否配置成功
[root@localhost blog]# php artisan tinker Psy Shell v0.10.8 (PHP 7.4.20 — cli) by Justin Hileman >>> app( es )->info() => [ "name" => "node-1", "cluster_name" => "my-application", "cluster_uuid" => "b-ovHR-GRvunpTmWOfoLKw", "version" => [ "number" => "7.12.1", "build_flavor" => "default", "build_type" => "docker", "build_hash" => "3186837139b9c6b6d23c3200870651f10d3343b7", "build_date" => "2021-04-20T20:56:39.040728659Z", "build_snapshot" => false, "lucene_version" => "8.8.0", "minimum_wire_compatibility_version" => "6.8.0", "minimum_index_compatibility_version" => "6.0.0-beta1", ], "tagline" => "You Know, for Search", ] >>>
使用 app( es )->info() 可以打印出es相关信息,则安装配置成功
在laravel中简单封装一个类来使用es
这里只以搜索为例,增删改都很简单,就不演示了
创建一个 service 类,来处理es搜索的结构体
<?php
/**
 * Created by PhpStorm
 * User: Ricky Wong
 * Date: 2021/8/1
 * Time: 19:58
 */
namespace AppServices;
class ElasticSearchService
{
    /**
     * 定义基础结构体
     * @var array
     */
    protected $params = [
         index  =>  products ,
         type  =>  _doc ,
         body  => [
             query  => [
                 bool  => [
                     filter  => [],
                     must   => []
                ]
            ]
        ]
    ];
    /**
     * 分页
     * @param int $size 每页显示多少条
     * @param int $page 页码
     * @return $this
     */
    public function paginate($size = 20, $page = 1)
    {
        $this->params[ body ][ from ] = ($page - 1) * $size;
        $this->params[ body ][ size ] = $size;
        return $this;
    }
    /**
     * 数据状态值准确查询
     * @param int $status 状态标识
     * @return $this
     */
    public function status($status = 1)
    {
        $this->params[ body ][ query ][ bool ][ filter ] = [
             term  => [ status  => $status]
        ];
        return $this;
    }
    /**
     * 排序
     * 如需多字段排序多次调用此方法即可
     * @param string $field 排序字段
     * @param string $direction 排序方式 asc|desc
     * @return $this
     */
    public function order($field, $direction)
    {
        if (!isset($this->params[ body ][ sort ])) {
            $this->params[ body ][ sort ] = [];
        }
        $this->params[ body ][ sort ][] = [$field => $direction];
        return $this;
    }
    /**
     * 关键词,按多字段权重搜索
     * @param array $keywords 搜索词数组
     * @return $this
     */
    public function keywords($keywords)
    {
        $keywords = is_array($keywords) ? $keywords : [$keywords];
        foreach ($keywords as $keyword) {
            $this->params[ body ][ query ][ bool ][ must ][] = [
                 multi_match  => [
                     query  => $keyword,
                     fields  => [
                         long_name^3 ,
                         name^2 
                    ],
                    // most_fields 多字段匹配度更高   best_fields  完全匹配占比更高
                     type  =>  most_fields 
                ]
            ];
        }
        return $this;
    }
    /**
     * 指定需要返回的字段
     * @param array $fields 字段数组
     * @return $this
     */
    public function select($fields = [])
    {
        $this->params[ body ][ _source ] = $fields;
        return $this;
    }
    /**
     * 搜索词高亮设置
     * @param array $fields 高亮搜索词数组
     * @return $this
     */
    public function highlight($fields)
    {
        $array = [];
        foreach ($fields as $field) {
            $array[$field] = (object)[];
        }
        $this->params[ body ][ highlight ] = [
            // 自定义高亮样式
             pre_tags  => "<p style= color: red; >",
             post_tags  => "</p>",
             fields  => $array
        ];
        return $this;
    }
    /**
     * 返回结构体
     * @return array
     */
    public function getParams()
    {
        return $this->params;
    }
}创建控制器,在其中定义方法来调用service,这里只展示这个方法
    /**
     * 搜索
     * @param Request $request
     * @param ElasticSearchService $service
     * @return IlluminateHttpJsonResponse
     */
    public function search(Request $request, ElasticSearchService $service)
    {
        $page = $request->input( page , 1);
        $size = $request->input( perPage , 20);
        $keyword =  $request->input( keyword ,   );
        $order = $request->input( order ,   );
        try {
            $builder = $service->status()->paginate($size, $page);
            if (!empty($keyword)) {
                // 将多个以空格隔开的关键词转为数组
                $keywords = array_filter(explode(   , $keyword));
                $builder->keywords($keywords);
            }
            if (!empty($order)) {
                if (preg_match( /^(.+)_(asc|desc)$/ , $order,$match)) {
                    $builder->order($match[1], $match[2]);
                }
            }
            $params = $builder->select([ name ,  long_name ])->highlight([ name ,  long_name ])->getParams();
            return response()->json([ result  => true,  data  => app( es )->search($params)]);
        } catch (Exception $e) {
            Log::error($e->getMessage());
            return response()->json([ result  => false,  data  => []]);
        }
    }