exercise / elastica-bundle
Requires
- php: >=5.3.2
- ruflin/elastica: 0.19.8
- symfony/console: >=2.1.0,<2.3-dev
- symfony/form: >=2.1.0,<2.3-dev
- symfony/framework-bundle: >=2.1.0,<2.3-dev
Requires (Dev)
- doctrine/mongodb-odm: 1.0.*@dev
- doctrine/orm: >=2.2,<2.5-dev
- propel/propel1: 1.6.*
Suggests
- doctrine/mongodb-odm: 1.0.*@dev
- doctrine/orm: >=2.2,<2.5-dev
- propel/propel1: 1.6.*
This package is not auto-updated.
Last update: 2022-02-01 12:20:11 UTC
README
注意:此软件包已迁移至FOSElasticaBundle,位于FriendsOfSymfony组织下。
Elastica在Symfony2中的集成
安装
安装elasticsearch
http://www.elasticsearch.org/guide/reference/setup/installation.html
安装Elastica
下载
使用子模块
git submodule add git://github.com/ruflin/Elastica vendor/elastica
使用克隆
git clone git://github.com/ruflin/Elastica vendor/elastica
使用供应商脚本
将以下行添加到您的deps文件中
[Elastica]
    git=git://github.com/ruflin/Elastica.git
    target=elastica
注册自动加载
// app/autoload.php
$loader->registerPrefixes(array(
    ...
    'Elastica' => __DIR__.'/../vendor/elastica/lib',
));
安装ElasticaBundle
仅使用Symfony2 master分支的master分支,使用2.0分支与Symfony2.0.x版本一起使用。
下载
使用子模块
git submodule add git://github.com/Exercise/FOQElasticaBundle vendor/bundles/FOQ/ElasticaBundle
使用克隆
git clone git://github.com/Exercise/FOQElasticaBundle vendor/bundles/FOQ/ElasticaBundle
使用供应商脚本
将以下行添加到您的deps文件中
[FOQElasticaBundle]
    git=git://github.com/Exercise/FOQElasticaBundle.git
    target=bundles/FOQ/ElasticaBundle
对于与Symfony2.0.x版本一起使用的2.0分支,请添加以下内容
[FOQElasticaBundle]
    git=git://github.com/Exercise/FOQElasticaBundle.git
    target=bundles/FOQ/ElasticaBundle
    version=origin/2.0
运行供应商脚本
$ php bin/vendors install
注册自动加载
// app/autoload.php
$loader->registerNamespaces(array(
    ...
    'FOQ' => __DIR__.'/../vendor/bundles',
));
注册软件包
// app/AppKernel.php
public function registerBundles()
{
    return array(
        // ...
        new FOQ\ElasticaBundle\FOQElasticaBundle(),
        // ...
    );
}
基本配置
声明一个客户端
Elasticsearch客户端类似于数据库连接。大多数情况下,您只需要一个。
#app/config/config.yml
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
声明一个索引
Elasticsearch索引类似于Doctrine实体管理器。大多数情况下,您只需要一个。
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
在此,我们创建了一个名为"website"的索引,它使用我们的"default"客户端。
我们的索引现在作为服务可用:foq_elastica.index.website。它是一个Elastica_Index实例。
如果您需要具有与服务名称不同的索引名称,例如,为了在不同环境中使用不同的索引,则可以使用index_name密钥来更改索引名称。服务名称将在不同环境中保持相同
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            index_name: website_qa
服务ID将是foq_elastica.index.website,但底层索引名称是website_qa。
声明一个类型
Elasticsearch 类型类似于 Doctrine 实体仓库。
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                user:
                    mappings:
                        username: { boost: 5 }
                        firstName: { boost: 3 }
                        lastName: { boost: 3 }
                        aboutMe: ~
我们的类型现在可以作为服务使用:foq_elastica.index.website.user。它是 Elastica_Type 的一个实例。
声明父字段
foq_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    indexes:
        website:
            client: default
            types:
                comment:
                    mappings:
                        post: {_parent: { type: "post", identifier: "id" } }
                        date: { boost: 5 }
                        content: ~
声明 nested 或 object
foq_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 foq:elastica:populate
此命令会删除并创建声明的索引和类型。它将配置的映射应用于类型。
此命令需要提供程序以在 Elasticsearch 类型中插入新文档。有两种创建提供程序的方法。如果你的 Elasticsearch 类型与 Doctrine 仓库或 Propel 查询匹配,请选择持久性自动提供程序。或者,为了获得完全的灵活性,请选择手动提供程序。
持久性自动提供程序
如果我们想从 Doctrine 仓库或 Propel 查询中索引实体,一些配置将让 ElasticaBundle 为我们完成。
foq_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
手动提供程序
创建一个具有 "foq_elastica.provider" 标签的服务,并具有服务将为其提供索引和类型的属性。
    <service id="acme.search_provider.user" class="Acme\UserBundle\Search\UserProvider">
        <tag name="foq_elastica.provider" index="website" type="user" />
        <argument type="service" id="foq_elastica.index.website.user" />
    </service>
它的类必须实现 FOQ\ElasticaBundle\Provider\ProviderInterface。
    <?php
    namespace Acme\UserBundle\Provider;
    use FOQ\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/FOQ/ElasticaBundle/Doctrine/AbstractProvider.php 中找到更完整的实现示例。
搜索
您可以使用作为服务提供的索引和类型 Elastica 对象来执行搜索。
/** var Elastica_Type */
$userType = $this->container->get('foq_elastica.index.website.user');
/** var Elastica_ResultSet */
$resultSet = $userType->search('bob');
Doctrine/Propel 查找器
如果您的 Elasticsearch 类型绑定到 Doctrine 实体仓库或 Propel 查询,则执行搜索时,您可以获取实体而不是 Elastica 结果。在您的配置中声明您想要 Doctrine/Propel 查找器。
foq_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: ~
您现在可以使用 foq_elastica.finder.website.user 服务
/** var FOQ\ElasticaBundle\Finder\TransformedFinder */
$finder = $container->get('foq_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 FOQ\ElasticaBundle\HybridResult */
$hybridResults = $finder->findHybrid('bob');
foreach ($hybridResults as $hybridResult) {
    /** var  Acme\UserBundle\Entity\User */
    $user = $hybridResult->getTransformed();
    /** var  Elastica_Result */
    $result = $hybridResult->getResult();
}
索引范围查找器
您还可以定义一个将在整个索引上工作的查找器。根据以下说明调整您的索引配置
foq_elastica:
    indexes:
        website:
            client: default
            finder: ~
您现在可以使用索引范围查找器服务 foq_elastica.finder.website
/** var FOQ\ElasticaBundle\Finder\MappedFinder */
$finder = $container->get('foq_elastica.finder.website');
// Returns a mixed array of any objects mapped
$results = $finder->find('bob');
仓库
除了为特定的 Doctrine/Propel 实体使用查找服务外,您还可以为每个驱动程序使用管理服务,以获取一个用于搜索的实体仓库。这允许您使用相同的服务而不是特定的查找服务。例如
/** var FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager.orm');
/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');
/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');
您也可以指定实体的全名,而不是使用快捷语法
/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('Application\UserBundle\Entity\User');
2.0 分支不支持使用
UserBundle:User风格的语法,您必须使用实体的全名。
默认管理器
如果您只使用一个驱动程序,则其管理服务将自动别名为 foq_elastica.manager。因此,上面的例子可以简化为
/** var FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager');
/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');
/** var array of Acme\UserBundle\Entity\User */
$users = $repository->find('bob');
如果您使用多个驱动程序,则可以使用 default_manager 参数选择哪个别名为 foq_elastica.manager
foq_elastica:
    default_manager: mongodb #defauults to orm
    clients:
        default: { host: localhost, port: 9200 }
    #--
自定义仓库
除了默认仓库外,您还可以为实体创建自定义仓库,并添加特定搜索的方法。这些方法需要扩展 FOQ\ElasticaBundle\Repository 以访问查找器
<?php
namespace Acme\ElasticaBundle\SearchRepository;
use FOQ\ElasticaBundle\Repository;
class UserRepository extends Repository
{
    public function findWithCustomQuery($searchText)
    {
        // build $query with Elastica objects
        $this->find($query);
    }
}
要使用自定义仓库,请在实体的映射中指定它
foq_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 FOQ\ElasticaBundle\Manager\RepositoryManager */
$repositoryManager = $container->get('foq_elastica.manager');
/** var FOQ\ElasticaBundle\Repository */
$repository = $repositoryManager->getRepository('UserBundle:User');
/** var array of Acme\UserBundle\Entity\User */
$users = $repository->findWithCustomQuery('bob');
或者,您可以使用实体中的注解来指定自定义仓库
<?php
namespace Application\UserBundle\Entity;
use FOQ\ElasticaBundle\Configuration\Search;
/**
 * @Search(repositoryClass="Acme\ElasticaBundle\SearchRepository\UserRepository")
 */
class User
{
   //---
}
实时、选择性索引更新
如果您使用 Doctrine 集成,可以在对象被添加、更新或删除时自动让 ElasticaBundle 更新索引。它使用 Doctrine 生命周期事件。声明您希望实时更新索引
foq_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 时,无需重新填充整个 "user" 索引。
您还可以选择仅监听某些事件
                    persistence:
                        listener:
                            insert: true
                            update: false
                            delete: true
Propel 目前不支持此功能。
检查实体方法以用于监听器
如果您使用监听器来更新您的索引,您可能需要在索引它们之前验证您的实体(例如,仅索引 "public" 实体)。通常,您希望监听器与提供者的查询条件保持一致。这可以通过使用 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 时,新实体才会被索引。另外,修改的实体将根据回调返回 true 或 false 分别更新或从索引中删除。删除监听器不考虑回调。
Propel 目前不支持此功能。
高级 Elasticsearch 配置
在声明类型时可以指定任何设置。例如,要启用自定义分析器,可以编写
foq_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异常。根据您的需求,可能希望抑制这些异常,并允许搜索静默失败。
实现这一目标的一种方法是用自定义类覆盖foq_elastica.client.class服务容器参数。在以下示例中,我们覆盖了Client::request()方法,并在发生异常时返回等效的空搜索响应。
<?php
namespace Acme\ElasticaBundle;
use FOQ\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":[]}}');
        }
    }
}
高级查询示例
如果您想执行更高级的查询,这里有一个使用雪球词干算法的示例。
它使用title、tags和categoryIds搜索文章实体。结果必须至少匹配一个指定的categoryIds,并且应匹配title或tags标准。此外,我们定义了一个雪球分析器,用于对title字段上的查询应用。
$finder = $this->container->get('foq_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);
配置
foq_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: