heyday/silverstripe-elastica

为 SilverStripe DataObjects 提供 Elastic Search 集成,使用 Elastica

安装数: 28,629

依赖关系: 2

建议者: 0

安全性: 0

星级: 11

关注者: 23

分支: 22

类型:silverstripe-vendormodule

4.3.0 2024-02-07 03:25 UTC

README

简化了使用 ElasticSearch 进行 SilverStripe CMS 搜索和索引的过程。我们使用 Elastica 来处理与弹性搜索服务器的通信。

此模块使得在不限制 Elastica 中发现的功能的情况下使用 ElasticSearch 变得很容易。基本上,所有可以单独使用 Elastica 完成的事情都可以与这个模块一起完成。

此模块取代了 Symbiote 的 Elastica 模块,该模块只支持到 SilverStripe 3。

功能

  • 使用 Elastica 与 ElasticSearch 服务器通信
  • 使用 PSR/Log 接口进行日志记录(可选)
  • 使用 YAML 配置来索引数据对象和页面
  • 可以处理索引的 ElasticSearch 文档中的 has_many、many_many 和 has_one 关系
  • 可以处理相关数据对象的失效和重新索引
  • 可以处理仅存在于对象实例中而不是数据库中的自定义字段
  • 从对应 SilverStripe 模型中定义的数据库字段类型推断 ElasticSearch 文档字段类型

兼容性

此版本应与所有 7.0 及以上版本的 ElasticSearch 兼容。可能与 6.x 版本的 Elasticsearch 一起工作。此版本需要 SilverStripe 4.x

如果您需要与更早版本的 Elasticsearch (2.x) 和 SS (3.x) 一起工作,请尝试此模块的 1.0 版本

安装

$ composer require heyday/silverstripe-elastica

用法

Elastica 服务配置示例

mysite/_config/search.yml

Heyday\Elastica\ElasticaService: # Example of customising the index config on the elastic search server (completely optional).
  index_config:
    settings:
      analysis:
        analyzer:
          default:
            type: custom
            tokenizer: standard
            filter:
              - lowercase
              - stemming_filter
        filter:
          stemming_filter:
            type: snowball
            language: English

---
Only:
  environment: dev
---
SilverStripe\Core\Injector\Injector:
  Elastica\Client:
    constructor:
      - host: localhost # hostname of the elastic search server
        port: 9200 # port number of the elastic search server

  Heyday\Elastica\ElasticaService:
    constructor:
      - "%$Elastica\Client"
      - "name-of-index"  # name of the index on the elastic search server
      - "%$Logger"  # your error logger (must implement psr/log interface)
      - "64MB"      # increases memory limit while indexing

索引配置示例

mysite/_config/search.yml

# PageTypes

Your\Namespace\Page:
  extensions:
    - Heyday\Elastica\Searchable
  indexed_fields: &page_defaults
    - Title
    - MenuTitle
    - Content
    - MetaDescription

Your\Namespace\SpecialPageWithAdditionalFields:
  extensions:
    - Heyday\Elastica\Searchable # only needed if this page does not extend the 'Page' configured above
  indexed_fields:
    <<: *page_defaults
    - BannerHeading
    - BannerCopy
    - SubHeading

Your\Namespace\SpecialPageWithRelatedDataObject:
  extensions:
    - Heyday\Elastica\Searchable
  indexed_fields:
    <<: *page_defaults
    -
      RelatedDataObjects:
        type: nested
        relationClass: App\DataObjects\Tags # Will be pulled from has_many / many_many, but you can specify it here too

Your\Namespace\RelatedDataObject:
  extensions:
    - Heyday\Elastica\Searchable
  indexed_fields:
    - Title
    - SomeOtherField
  dependent_classes:
    - SpecialPageWithRelatedDataObject # invalidates the index for SpecialPageWithRelatedDataObject when a RelatedDataObject is updated/created

自定义字段索引配置示例

mysite/_config/search.yml

# PageTypes

Your\Namespace\Page:
  extensions:
    - Heyday\Elastica\Searchable
  indexed_fields:
    - Title
    - SomeOtherField
    -
      TitleAlias:
        type: text
        field: Title # You can specify a custom internal field value with 'field'
    -
      SomeCustomFieldSimple:
        type: text
    -
      SomeCustomFieldComplicatedConfig:
        type: text
        analyzer: nGram_analyser # Must reference analyzer defined on index_config
        search_analyzer: whitespace_analyser # Must reference analyzer defined on index_config
        store: true

mysite/code/PageTypes/Page.php

<?php

class Page extends SiteTree
{
    public function getSomeCustomFieldSimple()
    {
        return 'some dynamic text or something';
    }

    public function getSomeCustomFieldComplicatedConfig()
    {
        return 'the config does not have anyting to do with me';
    }
}

简单搜索控制器配置/实现示例

mysite/_config/search.yml

  SearchController:
    properties:
      SearchService: "%$Heyday\Elastica\ElasticaService"

mysite/code/Controllers/SearchController.php

<?php

class SearchController extends Page_Controller
{
    /**
     * @var array
     */
    private static $allowed_actions = [
        'index'
    ];

    /**
     * @var \Heyday\Elastica\ElasticaService
     */
    protected $searchService;

    /**
     * Search results page action
     *
     * @return HTMLText
     */
    public function index()
    {
        return $this->renderWith(['SearchResults', 'Page']);
    }

    /**
     * @param \Heyday\Elastica\ElasticaService $searchService
     */
    public function setSearchService(\Heyday\Elastica\ElasticaService $searchService)
    {
        $this->searchService = $searchService;
    }

    /**
     * @return bool|\Heyday\Elastica\PaginatedList
     */
    public function Results()
    {
        $request = $this->getRequest();

        if ($string = $request->requestVar('for')) {

            $query = new \Elastica\Query\BoolQuery();

            $query->addMust(
                new \Elastica\Query\QueryString(strval($string))
            );

            $results = $this->searchService->search($query);

            return new \Heyday\Elastica\PaginatedList($results, $request);
        }

        return false;
    }

    /**
     * Query all Page fields and RelatedObjects nested fields.
     *
     * @return bool|\SilverStripe\ORM\PaginatedList
     */
    public function ResultsWithRelatedObjects()
    {
        $request = $this->getRequest();

        if ($string = $request->requestVar('for')) {

            $queryString = new \Elastica\Query\QueryString(strval($string));

            $boolQuery = new \Elastica\Query\BoolQuery();

            $nestedQuery = new \Elastica\Query\Nested();
            $nestedQuery->setPath('RelatedDataObjects');
            $nestedQuery->setQuery($queryString);

            $boolQuery->addShould($queryString);
            $boolQuery->addShould($nestedQuery);

            $results = $this->searchService->search($boolQuery);

            return new \SilverStripe\ORM\PaginatedList($results, $request);
        }

        return false;
    }

    /**
     * @return mixed
     */
    public function SearchString()
    {
        return Convert::raw2xml($this->getRequest()->requestVar('for'));
    }
}

重新索引

要运行 Elastica 的完整重新索引,请使用

./vendor/bin/sake dev/tasks/ElasticaReindexTask

使用队列

您可以使用队列来在后台运行重新索引过程。

我们使用 silverstripe-queuedjobs (https://github.com/symbiote/silverstripe-queuedjobs) 并创建了一个重新索引的任务。

要开启队列,您需要以下配置

SilverStripe\Core\Injector\Injector:
  Heyday\Elastica\Searchable:
    properties:
      queued: true

您还需要设置一个 cronjob(我知道这不太像队列...)

每分钟运行队列中的任务

*/1 * * * * php /path/to/silverstripe/framework/cli-script.php dev/tasks/ProcessJobQueueTask

并且为了清理任务,运行一次(然后它将自动添加为每天运行一次)

framework/sake dev/tasks/CreateQueuedJobTask?name=Symbiote\QueuedJobs\Jobs\CleanupJob