god-jay/scout-elasticsearch

v1.0.1 2021-12-20 11:30 UTC

This package is auto-updated.

Last update: 2024-09-20 18:18:39 UTC


README

在 Laravel 应用程序中使用 Elasticsearch 与使用 Eloquent ORM 一样简单。

英语 | 简体中文

内容

安装

您可以通过 composer 安装此包

composer require god-jay/scout-elasticsearch

安装包后,您应使用 vendor:publish Artisan 命令发布 Scout 配置。此命令将 scout.php 配置文件发布到您的配置目录

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

然后添加

SCOUT_DRIVER=elastic
ELASTICSEARCH_HOST=your_es_host_ip:port

#Add if should auth es user
ELASTICSEARCH_USER=your_es_user
ELASTICSEARCH_PASS=your_es_pass

使用 Docker Compose 运行 es + kibana

如果您没有自己的 es 服务,您可以使用 docker compose 安装并运行 es + kibana

  • 您首先应安装 docker compose: 安装 docker compose

  • 然后在目录根运行该命令

    docker-compose up -d
  • 您可以通过 https://:5601 浏览 kibana。

  • 要停止 docker 容器,请在目录根运行该命令

    docker-compose down

在您的 .env 文件中。

配置

假设有一个 posts 表和一个 Post 模型,简化后的表可能如下所示

在模型中使用 GodJay\ScoutElasticsearch\Searchable

namespace App\Models;

use GodJay\ScoutElasticsearch\Searchable;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use Searchable;
}

在模型中添加 searchableAs 函数

public function searchableAs()
{
    //elasticsearch index name, you can set any name you like in the model
    return 'posts';
}

使用

创建 Elasticsearch 索引

在模型中添加 getElasticMapping 函数

然后运行 php artisan elastic:create-index "App\Models\Post"

有关更多详细信息,请参阅 创建索引 API

public function getElasticMapping()
{
    return [
        'title' => [
            'type' => 'text',
            'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart',
        ],
        'content' => [
            'type' => 'text',
            'analyzer' => 'ik_max_word',
            'search_analyzer' => 'ik_smart',
        ],
    ];
}

Elasticsearch 索引将如下所示

{
  "mapping": {
    "_doc": {
      "properties": {
        "content": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        }
      }
    }
  }
}

将给定的模型导入到搜索索引中

如果您的表中已经存在许多行,并且您想将这些行导入到 Elasticsearch 中

在模型中添加 toSearchableArray 函数,然后运行 php artisan scout:import "App\Models\Post"

public function toSearchableArray()
{
    return [
       'id' => $this->attributes['id'],
       'title' => $this->attributes['title'],
       'content' => strip_tags($this->attributes['content']),
       'created_at' => $this->attributes['created_at'],
   ];
}

从上面的表中导入行后,Elasticsearch 索引将如下所示

{
  "mapping": {
    "_doc": {
      "properties": {
        "content": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        },
        "created_at": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "id": {
          "type": "long"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart"
        }
      }
    }
  }
}

从索引中清除模型的所有记录

运行 php artisan scout:flush "App\Models\Post"

添加记录

一旦您将 Searchable 特性添加到模型中,您只需保存模型实例,它就会自动添加到您的搜索索引中。

$post = new Post();

// ...

$post->save();

更新记录

要更新可搜索的模型,您只需更新模型实例的属性并将模型保存到数据库中。

$post = Post::find(1);

// Update the order...

$post->save();

删除记录

要从索引中删除记录,请从数据库中删除模型。这种删除方式甚至与软删除模型兼容

$post = Post::find(1);

$post->delete();

搜索

基础

$posts = Post::search('内容')->get();

分页

$posts = Post::search('内容')->paginate(10);

高亮显示

$post = Post::search('内容')->highlight(['title' => null, 'content' => null])->first();

搜索结果将是

App\Models\Post Object
(
    [table:protected] => ppp
    ...
    [attributes:protected] => [
        [id] => 1
        [title] => 标题
        [content] => 文本内容
        [created_at] => 2020-01-01 01:01:01
    ]
    [relations:protected] => [
        [highlight] => GodJay\ScoutElasticsearch\Highlight Object
        (
            [attributes:protected] => [
                [content] => [
                    [0] => 文本<em>内容</em>
                ]
            ]
        )
    ]
)

高级使用

ES 脚本排序

use GodJay\ScoutElasticsearch\ElasticsearchEngine;

$posts = Post::search('', function (ElasticsearchEngine $engine, string $query, array $params) {
    $params['body']['sort'] = array_merge([[
        '_script' => [
            'type' => 'number',
            'script' => ['source' => "doc['field_a'].value * 0.7 + doc['field_b'].value * 0.3"],
            'order' => 'desc'
        ]
    ]], $params['body']['sort'] ?? []);
    $engine->setQueryParams($params);
    return $engine;
})->orderBy('id', 'desc')->where('field_c', 1)->get();

调试

use GodJay\ScoutElasticsearch\ElasticsearchEngine;

$debug = Post::search('', function (ElasticsearchEngine $engine, string $query, array $params) {
    $params['body']['sort'] = array_merge([[
        '_script' => [
            'type' => 'number',
            'script' => ['source' => "doc['field_a'].value * 0.7 + doc['field_b'].value * 0.3"],
            'order' => 'desc'
        ]
    ]], $params['body']['sort'] ?? []);
    $engine->setQueryParams($params);
    return $engine;
})->orderBy('id', 'desc')->where('field_c', 1)->where('field_d', ['x', 'y'])->debugSearch();

结果将是

Array
(
    [result] => Illuminate\Database\Eloquent\Collection Object
    ...
    [query_params] => Array
    ...
    [exception] => 
    ...
)

$debug['query_params'] 的 json 字符串将是

{
  "index": "posts",
  "body": {
    "sort": [
      {
        "_script": {
          "type": "number",
          "script": {
            "source": "doc['field_a'].value * 0.7 + doc['field_b'].value * 0.3"
          },
          "order": "desc"
        }
      },
      {
        "id": "desc"
      }
    ],
    "query": {
      "bool": {
        "must": [
          {
            "match_phrase": {
              "field_c": 1
            }
          },
          {
            "terms": {
              "field_d": [
                "x",
                "y"
              ]
            }
          }
        ]
      }
    }
  }
}