用elasticsearch-php laravel为什么不能返回高亮数据

发布网友 发布时间:2022-04-28 03:31

我来回答

2个回答

懂视网 时间:2022-04-28 07:52

下面由Laravel教程栏目给大家介绍如何轻松集成新版Elasticsearch7.9中文搜索到Laravel7项目,希望对需要的朋友有所帮助!


ar414 5分钟 集成新版 Elasticsearch7.9 中文搜索 到你的 Laravel7 项目

只需五步骤:

1.启动 集成ik中文分词插件的Elasticsearch7.9 Docker镜像
2.Laravel7 配置 Scout
3.配置 Model模型
4.导入数据
5.搜索

演示地址

ar414 5分钟 集成新版 Elasticsearch7.9 中文搜索 到你的 Laravel7 项目

www.ar414.com/search?query=php%E5%...

搜索范围

  • 文章内容
  • 标题
  • 标签
  • 结果权重

    1. 出现关键词数量
    2. 出现关键词次数

    搜索页面

  • 高亮显示
  • 分词显示
  • 结果分页
  • 前言

    主要是博客刚好想做个搜索,顺便就整理成文章

    Laravel + Elasticsearch 很多前辈都写过教程和案例,但是随着Elasticsearch和laravel的版本升级 以前的文章很多都不适用新版本的,建议大家使用任何开源项目时应该过一遍文档以当前使用的版本文档为主,教程为辅

  • Elasticsearch 7.9
  • Laravel 7
  • elasticsearch-analysis-ik v7.9
  • 参考

  • ik 中文分词插件
  • elasticsearch 官方文档
  • 使用集成ik中文分词插件的Elasticsearch

    拉取docker

    $ docker pull ar414/elasticsearch-7.9-ik-plugin

    创建日志和数据存储目录

    本地映射到docker容器内,防止docker重启数据丢失

    $ mkdir -p /data/elasticsearch/data
    $ mkdir -p /data/elasticsearch/log
    $ chmod -R 777 /data/elasticsearch/data
    $ chmod -R 777 /data/elasticsearch/log

    运行

    docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -v /data/elasticsearch/data:/var/lib/elasticsearch -v /data/elasticsearch/log:/var/log/elasticsearch ar414/elasticsearch-7.9-ik-plugin

    验证

    $ curl http://localhost:9200{
     "name" : "01ac21393985", "cluster_name" : "docker-cluster", "cluster_uuid" : "h8L336qcRb2i1aydOv04Og", "version" : {
     "number" : "7.9.0", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "a479a2a7fce03512d6a9361301708b92dff667", "build_date" : "2020-08-11T21:36:48.204330Z", "build_snapshot" : false, "lucene_version" : "8.6.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1"
     }, "tagline" : "You Know, for Search"}

    测试中文分词

    curl -X POST "http://localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d'
    {
     "analyzer": "ik_max_word",
     "text": "laravel天下无敌"
    }
    '{
     "tokens" : [
     {
     "token" : "laravel", "start_offset" : 0, "end_offset" : 7, "type" : "ENGLISH", "position" : 0 }, {
     "token" : "天下无敌", "start_offset" : 7, "end_offset" : 11, "type" : "CN_WORD", "position" : 1 }, {
     "token" : "天下", "start_offset" : 7, "end_offset" : 9, "type" : "CN_WORD", "position" : 2 }, {
     "token" : "无敌", "start_offset" : 9, "end_offset" : 11, "type" : "CN_WORD", "position" : 3 }
     ]}

    Laravel 项目中使用 Elasticsearch

    matchish/laravel-scout-elasticsearch
    Elasticsearch官方有提供 SDK,在 Laravel 项目中可以更加优雅快速的接入 Elasticsearch,Laravel 本身有提供 Scout全文搜索 的解决方案,我们只需将默认的 Algolia 驱动 替换成ElasticSearch驱动

    安装

  • laravel/scout
  • matchish/laravel-scout-elasticsearch
    $ composer require laravel/scout
    $ composer require matchish/laravel-scout-elasticsearch
  • 配置

    1. 生成 Scout 配置文件(config/scout.php)

      $ php artisan vendor:publish --provider="LaravelScoutScoutServiceProvider"Copied File [vendorlaravelscoutconfigscout.php] To [configscout.php]Publishing complete.
    2. 指定 Scout 驱动

  • 第一种:在.env文件中指定(建议)
    SCOUT_DRIVER=MatchishScoutElasticSearchEnginesElasticSearchEngine
  • 第二种:在config/scout.php直接修改默认驱动
    'driver' => env('SCOUT_DRIVER', 'algolia')改为'driver' => env('SCOUT_DRIVER', 'MatchishScoutElasticSearchEnginesElasticSearchEngine')
    1. 指定Elasticsearch服务IP端口

      如果使用docker部署则使用docker0的IP,Linux通过ifconfig查看

      .env中配置

      ELASTICSEARCH_HOST=172.17.0.1:9200
    2. 注册服务
      config/app.php

      'providers' => [
       // Other Service Providers
       MatchishScoutElasticSearchElasticSearchServiceProvider::class],
    3. 清除配置缓存

      $ php artisan config:clear

    至此 laravel 已经接入 Elasticsearch

    实际业务中使用

    需求

    14分钟14秒 集成 Elasticsearch中文搜索 到你的 Laravel 项目

    通过博客右上角的搜索框可以搜索到与关键词相关的文章,从以下几点匹配

  • 文章内容
  • 文章标题
  • 文章标签
  • 涉及到2张 Mysql表 以及字段

  • article
  • title
  • tags
  • article_content
  • content
  • 为文章配置 Elasticsearch 索引

    1. 创建索引配置文件(config/elasticsearch.php)

      $ touch config/elasticsearch.php
    2. elasticsearch.php 配置字段映射

      <?phpreturn [
       'indices' => [
       'mappings' => [
        'blog-articles' => [
        "properties"=> [
         "content"=> [
         "type"=> "text",
         "analyzer"=> "ik_max_word",
         "search_analyzer"=> "ik_smart"
         ],
         "tags"=> [
         "type"=> "text",
         "analyzer"=> "ik_max_word",
         "search_analyzer"=> "ik_smart"
         ],
         "title"=> [
         "type"=> "text",
         "analyzer"=> "ik_max_word",
         "search_analyzer"=> "ik_smart"
         ]
        ]
        ]
       ]
       ],];
  • analyzer:字段文本的分词器
  • search_analyzer:搜索词的分词器
  • 根据具体业务场景选择(颗粒小占用资源多,一般场景analyzer使用ik_max_word,search_analyzer使用ik_smart):
  • ik_max_word:ik中文分词插件提供,对文本进行最大数量分词
    laravel天下无敌 -> laravel天下无敌,天下,无敌
  • ik_smart: ik中文分词插件提供,对文本进行最小数量分词
    laravel天下无敌 -> laravel天下无敌
  • 配置文章模型

    建议先看一遍 Laravel Scout 使用文档

    1. 引入Laravel Scout

       namespace AppModelsBlog;
      
       use LaravelScoutSearchable;
      
       class Article extends BlogBaseModel
       {
       use Searchable;
       }
    2. 指定索引(刚刚配置文件中的elasticsearch.indices.mappings.blog-articles)

       /**
       * 指定索引
       * @return string
       */
       public function searchableAs()
       {
       return 'blog-articles';
       }
    3. 设置导入索引的数据字段

       /**
       * 设置导入索引的数据字段
       * @return array
       */
       public function toSearchableArray()
       {
       return [
        'content' => ArticleContent::query()
        ->where('article_id',$this->id)
        ->value('content'),
        'tags' => implode(',',$this->tags),
        'title' => $this->title
       ];
       }
    4. 指定 搜索索引中存储的唯一ID

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

    数据导入

    其实是将数据表中的数据通过Elasticsearch导入到Lucene
    Elasticsearch 是 Lucene 的封装,提供了 REST API 的操作接口

  • 一键自动导入: php artisan scout:import
  • 导入指定模型: php artisan scout:import ${model}
  • $ php artisan scout:import "AppModelsBlogArticle"Importing [AppModelsBlogArticle]Switching to the new index
    5/5 [????????????????????????????] 100%[OK] All [AppModelsBlogArticle] records have been imported.

    导入失败,常见原因:

  • Unresolvable dependency resolving [Parameter #0 [ integer $retries ]] in class ElasticsearchTransport
  • 解决: 修改配置后,没有清除配置缓存
  • invalid_index_name_exception
  • 解决: searchableAs配置错误,为索引创建别名后,指定别名
  • 检查索引是否正确

    $ curl -XGET http://localhost:9200/blog-articles/_mapping?pretty{
     "blog-articles_1598362919" : {
     "mappings" : {
     "properties" : {
     "__class_name" : {
      "type" : "text",  "fields" : {
      "keyword" : {
      "type" : "keyword",  "ignore_above" : 256  }
      }
     }, "content" : {
      "type" : "text",  "analyzer" : "ik_max_word",  "search_analyzer" : "ik_smart"
     }, "tags" : {
      "type" : "text",  "analyzer" : "ik_max_word",  "search_analyzer" : "ik_smart"
     }, "title" : {
      "type" : "text",  "analyzer" : "ik_max_word",  "search_analyzer" : "ik_smart"
     }
     }
     }
     }}

    测试

    1. 创建一个测试命令行

      $ php artisan make:command ElasticTest
    2. 代码

    <?phpnamespace AppConsoleCommands;use AppModelsBlogArticle;use AppModelsBlogArticleContent;use IlluminateConsoleCommand;use IlluminateSupportCarbon;class ElasticTest extends Command{
     /**
     * The name and signature of the console command.
     *
     * @var string
     */
     protected $signature = 'elasticsearch {query}';
    
     /**
     * The console command description.
     *
     * @var string
     */
     protected $description = 'elasticsearch test';
    
     /**
     * Create a new command instance.
     *
     * @return void
     */
     public function __construct()
     {
     parent::__construct();
     }
    
     /**
     * Execute the console command.
     *
     * @return mixed
     */
     public function handle()
     {
     //
     $startTime = Carbon::now()->getPreciseTimestamp(3);
     $articles = Article::search($this->argument('query'))->get()->toArray();
     $userTime = Carbon::now()->getPreciseTimestamp(3) - $startTime;
     echo "耗时(毫秒):{$userTime} 
    ";
    
     //content在另外一张表中,方便观察测试 这里输出
     if(!empty($articles)) {
      foreach($articles as &$article) {
      $article = ArticleContent::query()->where('article_id',$article['id'])->value('content');
      }
     }
    
     var_dump($articles);
    
     }}
    1. 测试
      $ php artisan elasticsearch 周杰伦

    ar414 5分钟 集成新版 Elasticsearch7.9 中文搜索 到你的 Laravel7 项目

    1. 复杂查询
      例如:自定义高亮显示
      //ONGRElasticsearchDSLHighlightHighlight ArticleModel::search($query,function($client,$body) {
        $higlight = new Highlight();
        $higlight->addField('content',['type' => 'plain']);
        $higlight->addField('title');
        $higlight->addField('tags');
        $body->addHighlight($higlight);
        $body->setSource(['title','tags']);
        return $client->search(['index' => (new ArticleModel())->searchableAs(), 'body' => $body->toArray()]);
       })->raw();

    复杂自定义查询回调中的$client和$body,可根据这两个包进行灵活操作

    $client 官方 elasticsearch/elasticsearch package(https://packagist.org/packages/elasticsearch/elasticsearch)

    $body ongr/elasticsearch-dsl package(https://packagist.org/packages/ongr/elasticsearch-dsl)

    热心网友 时间:2022-04-28 05:00

      自己重新写一个编辑器就可以了。

      1、已在本地windows机器上安装好了elasticsearch及相关插件。

      2、然后在laravel中安装好了elasticsearch-php客户端。

      3、写一个SearchController控制器就可以自己调动返回数据。

    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com