使用PHP Elastica和Symfony2 FosElasticaBundle计算查询

时间:2014-11-26 10:32:08

标签: elasticsearch elastica foselasticabundle

我正在使用FosElasticaBundle(@dev)进行Symfony 2.5.6项目。

在我的项目中,我只需要在弹性搜索中获取请求的总命中数。也就是说,我正在使用正常的请求查询弹性搜索,但通过特殊的"计数"网址

localhost:9200/_search?search_type=count

注意" search_type = count" URL参数。

以下是示例查询:

{
  "query": {
    "filtered": {
      "query": {
        "match_all": []
      },
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "media.category.id": [
                  681
                ]
              }
            }
          ]
        }
      }
    }
  },
  "sort": {
    "published_at": {
      "order": "desc"
    }
  },
  "size": 1
}

结果包含正常的JSON响应,但 hits部分中没有任何文档。从这个回复中我很容易得到总数:

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "hits": {
        "total": 81,
        "max_score": 0,
        "hits": [ ]
    }
}

好的,hits.total == 81

现在,我无法通过FOSElasticaBundle从存储库找到任何解决方案。

我试过了:

$query = (...) // building the Elastica query here
$count = $this->finder->findPaginated(
    $query,
    array(ES::OPTION_SEARCH_TYPE => ES::OPTION_SEARCH_TYPE_COUNT)
)->getNbResults();

但是我试图加载课程" Pagerfanta"。我不想要Pagerfanta。

然后这个:

$count = $this->finder->createPaginatorAdapter(
    $query,
    array(ES::OPTION_SEARCH_TYPE => ES::OPTION_SEARCH_TYPE_COUNT)
)->getTotalHits();

但它总会给我0。

如果我可以从存储库访问Elastica Finder服务(我可以从查询搜索中获取ResultSet,并且此ResultSet具有正确的getTotalHits()方法),那将很容易。但来自存储库的服务......你知道。

感谢您的帮助或线索!

3 个答案:

答案 0 :(得分:2)

我面临同样的挑战,从repo内部访问可搜索的界面。这就是我最终得到的结果:

创建AcmeBundle\Elastica\ExtendedTransformedFinder。这只是扩展TransformedFinder类并使searchable接口可访问。

<?php

namespace AcmeBundle\Elastica;

use FOS\ElasticaBundle\Finder\TransformedFinder;

class ExtendedTransformedFinder extends TransformedFinder
{

    /**
     * @return \Elastica\SearchableInterface
     */
    public function getSearch()
    {
        return $this->searchable;
    }

}

使捆绑使用我们的新类;在service.yml

parameters:
      fos_elastica.finder.class: AcmeBundle\Elastica\ExtendedTransformedFinder

然后在回购中使用我们班级的getSearch方法,做你想做的事情:)

class SomeSearchRepository extends Repository
{
    public function search(/* ... */)
    {
        // create and set your query as you like
        $query = Query::create();

        // ...

        // then run a count query
        $count = $this->finder->getSearch()->count($query);

    }
}

抬头这适用于3.1.x版本。应该从3.0.x开始。

答案 1 :(得分:1)

好的,所以,我们走了:不可能

从版本3.1.x-dev(2d8903a)开始,您不能从FOSElasticaBundle获取弹性搜索返回的匹配文档总数,因为此捆绑包不会公开此值。

RawPaginatorAdapter::getTotalHits()方法包含以下代码:

return $this->query->hasParam('size')
    ? min($this->totalHits, (integer) $this->query->getParam('size'))
    : $this->totalHits;

阻止在没有实际需要任何文档的情况下获取正确的$this->totalHits。实际上,如果将size设置为0,告诉elasticsearch不返回任何文档,只有元信息RawPaginatorAdapter::getTotalHits()将返回0。

所以FosElasticaBundle并没有提供一种了解这个总命中数的方法,你只能直接通过Elastica库来实现。当然,在\FOS\ElasticaBundle\Repository中,Elastica发现者可以在本地使用。您必须提供新服务,进行一些注射,并为您提供服务,而不是FOSElasticaBundle用于存储库......哎哟。

我选择了另一条路径,我分叉https://github.com/FriendsOfSymfony/FOSElasticaBundle并更改了方法代码,如下所示:

/**
 * Returns the number of results.
 *
 * @param boolean $genuineTotal make the function return the `hits.total`
 * value of the search result in all cases, instead of limiting it to the
 * `size` request parameter.
 * @return integer The number of results.
 */
public function getTotalHits($genuineTotal = false)
{
    if ( ! isset($this->totalHits)) {
        $this->totalHits = $this->searchable->search($this->query)->getTotalHits();
    }

return $this->query->hasParam('size') && !$genuineTotal
    ? min($this->totalHits, (integer) $this->query->getParam('size'))
    : $this->totalHits;
}

$genuineTotal boolean恢复弹性搜索行为,不引入任何BC中断。我也可以将它命名为$ignoreSize并以相反的方式使用它。

我打开了拉取请求:https://github.com/FriendsOfSymfony/FOSElasticaBundle/pull/748

我们会看到!如果这可以帮助一个人我已经开心了!

答案 2 :(得分:0)

虽然,您可以将索引实例作为服务(fos_elastica.index.INDEX_NAME.TYPE_NAME)获取并请求count()方法。