catch-of-the-day/elastica-bundle

此软件包已被放弃,不再维护。未建议替代软件包。

使用 Elastica 为您的 Symfony2 项目提供 Elasticsearch 集成

安装: 276

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 30

分支: 773

类型:symfony-bundle

v2.1.3 2013-11-25 09:43 UTC

README

Elastica 在 Symfony2 中的集成

安装

软件包和依赖项

对于 2.0.x 版本的 Symfony 项目,您必须使用此软件包的 1.x 版本。请检查软件包 标签Packagist 页面以获取有关 Symfony 和 Elastica 兼容性的信息。

将 FOSElasticaBundle 添加到您的应用程序的 composer.json 文件中

{
    "require": {
        "friendsofsymfony/elastica-bundle": "~2.0"
    }
}

使用以下命令安装软件包及其依赖项

$ php composer.phar update friendsofsymfony/elastica-bundle

您可以使用 Composer 来获取 Elastica 的适当版本。最后,在您的应用程序内核中启用此软件包

// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        // ...
        new FOS\ElasticaBundle\FOSElasticaBundle(),
    );
}

Elasticsearch

有关安装和部署 Elasticsearch 的说明,请参阅 此处

基本配置

声明客户端

Elasticsearch 客户端类似于数据库连接。大多数情况下,您只需要一个。

#app/config/config.yml
fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }

声明索引

Elasticsearch 索引类似于 Doctrine 实体管理器。大多数情况下,您只需要一个。

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default

我们创建了一个名为 "website" 的索引,它使用我们的 "default" 客户端。

我们的索引现在可以通过服务 fos_elastica.index.website 获取。它是一个 Elastica_Index 的实例。

如果您需要具有与服务名称不同的索引名称,例如,为了对不同环境使用不同的索引,则可以使用 index_name 键来更改索引名称。服务名称将在各个环境中保持相同。

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            index_name: website_qa

服务 ID 将为 fos_elastica.index.website,但底层索引名称为 website_qa。

声明类型

Elasticsearch 类型类似于 Doctrine 实体存储库。

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        username: { boost: 5 }
                        firstName: { boost: 3 }
                        lastName: { boost: 3 }
                        aboutMe: ~

我们的类型现在可以通过服务 fos_elastica.index.website.user 获取。它是一个 Elastica_Type 的实例。

声明父字段

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                comment:
                    mappings:
                        post: {_parent: { type: "post", identifier: "id" } }
                        date: { boost: 5 }
                        content: ~

声明 nestedobject

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                post:
                    mappings:
                        date: { boost: 5 }
                        title: { boost: 3 }
                        content: ~
                        comments:
                            type: "nested"
                            properties:
                                date: { boost: 5 }
                                content: ~

填充类型

php app/console fos:elastica:populate

此命令将删除并创建声明的索引和类型。它将配置的映射应用于类型。

此命令需要提供程序以将新文档插入到 elasticsearch 类型中。有两种创建提供程序的方法。如果您的 elasticsearch 类型与 Doctrine 存储库或 Propel 查询相匹配,请选择自动持久化提供程序。或者,为了获得最大的灵活性,请选择手动提供程序。

持久自动提供程序

如果我们想从Doctrine存储库或Propel查询中索引实体,一些配置将允许ElasticaBundle为我们完成这项工作。

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        username: { boost: 5 }
                        firstName: { boost: 3 }
                        # more mappings...
                    persistence:
                        driver: orm # orm, mongodb, propel are available
                        model: Application\UserBundle\Entity\User
                        provider: ~

实际上支持三种驱动程序:orm、mongodb和propel。

使用自定义Doctrine查询构建器

您可以通过指定自定义查询构建器方法来控制哪些实体将被索引。

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider:
                            query_builder_method: createIsActiveQueryBuilder

您的存储库必须实现此方法,并返回一个Doctrine查询构建器。

Propel目前还不支持此功能。

更改批量大小

默认情况下,ElasticaBundle将以100个文档为一组来索引文档。您可以在提供程序配置中更改此值。

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider:
                            batch_size: 100
更改文档标识符字段

默认情况下,ElasticaBundle将使用实体的id字段作为elasticsearch文档标识符。您可以在持久性配置中更改此值。

                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        identifier: id

手动提供程序

创建一个具有“fos_elastica.provider”标签和属性的服务,该服务将提供索引和类型。

    <service id="acme.search_provider.user" class="Acme\UserBundle\Search\UserProvider">
        <tag name="fos_elastica.provider" index="website" type="user" />
        <argument type="service" id="fos_elastica.index.website.user" />
    </service>

其类必须实现FOS\ElasticaBundle\Provider\ProviderInterface

    <?php

    namespace Acme\UserBundle\Provider;

    use FOS\ElasticaBundle\Provider\ProviderInterface;
    use Elastica_Type;

    class UserProvider implements ProviderInterface
    {
        protected $userType;

        public function __construct(Elastica_Type $userType)
        {
            $this->userType = $userType;
        }

        /**
         * Insert the repository objects in the type index
         *
         * @param Closure $loggerClosure
         */
        public function populate(Closure $loggerClosure = null)
        {
            if ($loggerClosure) {
                $loggerClosure('Indexing users');
            }

            $document = new \Elastica_Document();
            $document->setData(array('username' => 'Bob'));
            $this->userType->addDocuments(array($document));
        }
    }

您可以在src/FOS/ElasticaBundle/Doctrine/AbstractProvider.php中找到更完整的实现示例。

搜索

您可以使用作为服务提供的索引和类型Elastica对象来执行搜索。

/** var Elastica_Type */
$userType = $this->container->get('fos_elastica.index.website.user');

/** var Elastica_ResultSet */
$resultSet = $userType->search('bob');

Doctrine/Propel查找器

如果您的elasticsearch类型绑定到Doctrine实体存储库或Propel查询,则在执行搜索时,您可以获取实体而不是Elastica结果。在您的配置中声明您想要一个Doctrine/Propel查找器

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider: ~
                        finder: ~

您现在可以使用fos_elastica.finder.website.user服务

/** var FOS\ElasticaBundle\Finder\TransformedFinder */
$finder = $container->get('fos_elastica.finder.website.user');

/** var array of Acme\UserBundle\Entity\User */
$users = $finder->find('bob');

/** var array of Acme\UserBundle\Entity\User limited to 10 results */
$users = $finder->find('bob', 10);

您甚至可以得到分页结果!

Pagerfanta

/** var Pagerfanta\Pagerfanta */
$userPaginator = $finder->findPaginated('bob');

Knp分页器

$paginator = $this->get('knp_paginator');
$userPaginator = $paginator->paginate($finder->createPaginatorAdapter('bob'));

您还可以从查找器中同时获取Elastica结果和实体。然后您可以从Elastica_Result访问分数、高亮等,同时仍然获取实体。

/** var array of FOS\ElasticaBundle\HybridResult */
$hybridResults = $finder->findHybrid('bob');
foreach ($hybridResults as $hybridResult) {

    /** var  Acme\UserBundle\Entity\User */
    $user = $hybridResult->getTransformed();

    /** var  Elastica_Result */
    $result = $hybridResult->getResult();
}
索引宽查找器

您还可以定义一个将在整个索引上运行的查找器。根据以下内容调整您的索引配置

fos_elastica:
    indexes:
        website:
            client: default
            finder: ~

您现在可以使用索引宽查找器服务fos_elastica.finder.website

/** var FOS\ElasticaBundle\Finder\MappedFinder */
$finder = $container->get('fos_elastica.finder.website');

// Returns a mixed array of any objects mapped
$results = $finder->find('bob');

存储库

除了为特定的Doctrine/Propel实体使用查找器服务外,您还可以为每个驱动程序使用管理器服务,并为实体获取一个用于搜索的存储库。这允许您使用相同的而不是特定的服务。例如

/** var FOS\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('fos_elastica.manager.orm');

/** var FOS\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');

您还可以指定实体的全名而不是快捷语法

/** var FOS\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('Application\UserBundle\Entity\User');

2.0分支不支持使用UserBundle:User样式语法,您必须使用实体的全名。

默认管理器

如果您只使用一个驱动程序,则其管理器服务将自动别名为fos_elastica.manager。因此,上面的示例可以简化为

/** var FOS\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('fos_elastica.manager');

/** var FOS\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');

如果您使用多个驱动程序,则可以使用default_manager参数选择哪个别名为fos_elastica.manager

fos_elastica:
    default_manager: mongodb #defauults to orm
    clients:
        default: { host: localhost, port: 9200 }
    #--
自定义仓库

除了默认仓库,您还可以为实体创建一个自定义仓库,并为特定搜索添加方法。这些方法需要扩展 FOS\ElasticaBundle\Repository 以访问查询器

<?php

namespace Acme\ElasticaBundle\SearchRepository;

use FOS\ElasticaBundle\Repository;

class UserRepository extends Repository
{
    public function findWithCustomQuery($searchText)
    {
        // build $query with Elastica objects
        $this->find($query);
    }
}

要使用自定义仓库,请在实体的映射中指定它

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        provider: ~
                        finder: ~
                        repository: Acme\ElasticaBundle\SearchRepository\UserRepository

然后,在从管理器返回的仓库中使用时,将可以使用自定义查询

/** var FOS\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('fos_elastica.manager');

/** var FOS\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');

/** var array of Acme\UserBundle\Entity\User */
$users = $repository->findWithCustomQuery('bob');

或者,您可以使用实体中的注解来指定自定义仓库

<?php

namespace Application\UserBundle\Entity;

use FOS\ElasticaBundle\Configuration\Search;

/**
 * @Search(repositoryClass="Acme\ElasticaBundle\SearchRepository\UserRepository")
 */
class User
{

   //---

}

实时、选择性索引更新

如果您使用Doctrine集成,可以在对象添加、更新或删除时让ElasticaBundle自动更新索引。它使用Doctrine生命周期事件。声明您想要实时更新索引

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        # your mappings
                    persistence:
                        driver: orm
                        model: Application\UserBundle\Entity\User
                        listener: # by default, listens to "insert", "update" and "delete"

现在,每次绑定的Doctrine仓库的状态改变时,索引都会自动更新。无需在创建新的 User 时重新填充整个 "用户" 索引。

您还可以选择只监听某些事件

                    persistence:
                        listener:
                            insert: true
                            update: false
                            delete: true

Propel目前还不支持此功能。

检查实体方法以用于监听器

如果您使用监听器来更新索引,您可能需要在索引它们之前验证实体(例如,仅索引 "公开" 实体)。通常,您希望监听器与提供者的查询条件一致。这可以通过使用 is_indexable_callback 配置参数实现

                    persistence:
                        listener:
                            is_indexable_callback: "isPublic"

如果 is_indexable_callback 是一个字符串,并且实体具有指定的方法,监听器将仅索引返回 true 的实体。此外,您还可以提供服务和方法的名称对

                    persistence:
                        listener:
                            is_indexable_callback: [ "%custom_service_id%", "isIndexable" ]

在这种情况下,回调将是指定服务上的 isIndexable() 方法,将被考虑索引的对象作为唯一参数传递。这允许您进行更复杂的验证(例如,ACL检查)。

正如您所期望的,只有当回调返回 true 时,新实体才会被索引。此外,修改后的实体将根据回调返回 truefalse 分别更新或从索引中删除。删除监听器忽略回调。

Propel目前还不支持此功能。

忽略缺失的索引结果

默认情况下,FOSElasticaBundle会在从Elasticsearch返回的结果与其从所选持久化提供者找到的结果不同时抛出异常。这可能在大索引中存在问题,其中更新不会立即发生,或者另一个进程已从您的持久化提供者中删除了结果,但没有更新Elasticsearch。

您可能看到的错误类似于:'无法找到与所有Elastica结果对应的Doctrine对象'。

要解决这个问题,可以配置每个映射对象以忽略缺失的结果

                    persistence:
                        elastica_to_model_transformer:
                            ignore_missing: true

高级Elasticsearch配置

在声明类型时可以指定任何设置。例如,要启用自定义分析器,您可以编写

fos_elastica:
    indexes:
        doc:
            settings:
                index:
                    analysis:
                        analyzer:
                            my_analyzer:
                                type: custom
                                tokenizer: lowercase
                                filter   : [my_ngram]
                        filter:
                            my_ngram:
                                type: "nGram"
                                min_gram: 3
                                max_gram: 5
            types:
                blog:
                    mappings:
                        title: { boost: 8, analyzer: my_analyzer }

覆盖Client类以抑制异常

默认情况下,Elastica客户端库的异常将通过包的Client类传播。例如,如果Elasticsearch服务器离线,发出请求将导致抛出 Elastica_Exception_Client。根据您的需求,可能希望抑制这些异常并允许搜索静默失败。

实现这一目标的一种方法是用自定义类覆盖服务容器参数 fos_elastica.client.class。在以下示例中,我们覆盖了 Client::request() 方法,并在发生异常时返回一个空搜索响应的等效值。

<?php

namespace Acme\ElasticaBundle;

use FOS\ElasticaBundle\Client as BaseClient;

class Client extends BaseClient
{
    public function request($path, $method, $data = array())
    {
        try {
            return parent::request($path, $method, $data);
        } catch (\Elastica_Exception_Abstract $e) {
            return new \Elastica_Response('{"took":0,"timed_out":false,"hits":{"total":0,"max_score":0,"hits":[]}}');
        }
    }
}

高级查询示例

如果您想执行更高级的查询,这里有一个使用雪球词干算法的示例。

它通过 titletagscategoryIds 搜索文章实体。结果必须至少匹配一个指定的 categoryIds,并且应该匹配 titletags 的标准。此外,我们定义了一个雪球分析器,用于应用于对 title 字段的查询。

$finder = $this->container->get('fos_elastica.finder.website.article');
$boolQuery = new \Elastica_Query_Bool();

$fieldQuery = new \Elastica_Query_Text();
$fieldQuery->setFieldQuery('title', 'I am a title string');
$fieldQuery->setFieldParam('title', 'analyzer', 'my_analyzer');
$boolQuery->addShould($fieldQuery);

$tagsQuery = new \Elastica_Query_Terms();
$tagsQuery->setTerms('tags', array('tag1', 'tag2'));
$boolQuery->addShould($tagsQuery);

$categoryQuery = new \Elastica_Query_Terms();
$categoryQuery->setTerms('categoryIds', array('1', '2', '3'));
$boolQuery->addMust($categoryQuery);

$data = $finder->find($boolQuery);

配置

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        site:
            settings:
                index:
                  analysis:
                        analyzer:
                            my_analyzer:
                                type: snowball
                                language: English
            types:
                article:
                    mappings:
                        title: { boost: 10, analyzer: my_analyzer }
                        tags:
                        categoryIds:
                    persistence:
                        driver: orm
                        model: Acme\DemoBundle\Entity\Article
                        provider:
                        finder:

日期格式示例

如果您想指定一个 日期格式

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        site:
            types:
                user:
                    mappings:
                        username: { type: string }
                        lastlogin: { type: date, format: basic_date_time }
                        birthday: { type: date, format: "yyyy-MM-dd" }