elasticsearch api_platform产生错误“找不到URI [/index/_doc/_search]和方法[POST]的行程常式”

w6lpcovy  于 2022-11-22  发布在  ElasticSearch
关注(0)|答案(2)|浏览(113)

当尝试通过fos_elastica-bundle(v6.0.0)将elasticsearch(v7.9.3)实现到我的Symfony(v5.3.10)-应用程序与api_platform(v2.6.6)中时,我不断收到以下错误:

"{"error":"no handler found for uri [//posts/_doc/_search] and method [POST]"}",

我的api_platform.yaml的内容如下:

api_platform:
    [...]
    elasticsearch:
        hosts: [ '%env(ELASTICSEARCH_URL)%' ]
        mapping:
            App\Document\Post:
                index: posts

还有我的fos_elastica.yaml:

fos_elastica:
    clients:
        default: { url: '%env(ELASTICSEARCH_URL)%' }
    indexes:
        posts:
            properties:
                id:
                    "type": "keyword"
                source: ~
                title: ~
                description: ~
                body: ~
                children: ~
                tags: ~
                originalContent: ~
            persistence:
                driver: mongodb
                model: App\Document\Post

通过调试fos-elastica Bundle,我发现Elastica连接器正确地触发了一个[POST]请求,请求主体为“/posts/_doc/_search”:

{"sort":[{"id":{"order":"asc"}}],"query":{"match_all":{}},"size":30,"from":0}

如果我使用Kibana开发工具控制台并触发相同的请求

POST /posts/_doc/_search
  {"sort":[{"id":{"order":"asc"}}],"query":{"match_all":{}},"size":30,"from":60}

我从elasticsearch中得到了预期的结果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
    {
      "took" : 12,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 3082,
          "relation" : "eq"
        },
        "max_score" : null,
        "hits" : [
          {
            "_index" : "posts",
            "_type" : "_doc",
[...]

除了不赞成的通知,一切似乎都很好。
有人知道为什么fos_elastica-bundle的api_platform集成没有按预期工作,并且一直返回“no handler found”错误消息吗?

jdzmm42g

jdzmm42g1#

我现在已经帮助自己创建了一个自定义ApiResource - filter

#[ApiFilter(FulltextFilter::class, arguments: ['index' => 'post'], properties: ['body','description','tag'])]

我的自定义过滤器实现了ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface,直接与ElasticSearch服务器通信,发送一个查询来搜索指定的索引(post),并向aggregationBuilder添加另一个match()指令,其中包含一组与原始搜索匹配的ID:

<?php

declare(strict_types=1);

namespace App\Filter;

use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface;
use Doctrine\ODM\MongoDB\Aggregation\Builder;
use Elastica\Result;
use Elastica\Client;
use Elastica\Query;
use Symfony\Component\PropertyInfo\Type;

/**
 * Filter the collection by given properties.
 *
 */
final class FulltextFilter implements FilterInterface
{
    protected $index = '';
    protected $properties = [];
    protected $client;
    protected $searchParameterName;
    protected $maxResultsParameterName;
    const DEFAULT_MAX_RESULTS = 200;
    public function __construct(Client $client, string $index = '', string $maxResultsParameterName = 'amount', string $searchParameterName = 'query', array $properties = []) {
        $this->index = $index;
        $this->properties = $properties;
        $this->client = $client;
        $this->searchParameterName = $searchParameterName;
        $this->maxResultsParameterName = $maxResultsParameterName;
    }
    public function getFilteredIds($searchterm, $index = null, $properties = null, $maxResults = null) {
        $matches = [];
        if (is_null($properties)) {
            $properties = array_keys($this->properties);
        }
        foreach ($properties as $propertyName) {
            array_push($matches, ['match'=>[$propertyName => $searchterm]]);
        }
        $queryObject = ['query' => ['bool' => ['should' => $matches]]];
        $queryObject['size'] = (int) $maxResults >0 ? (int) $maxResults : self::DEFAULT_MAX_RESULTS;

        $query = new Query();
        $response = $this->client->getIndex($index ?? $this->index)
            ->search($query->setRawQuery($queryObject))
            ->getResults();
        return array_map(function(Result $result) {return $result->getHit()['_source']['id'];}, $response);

    }

    public function apply(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array &$context = [])
    {
        $maxResults = $context['filters'][$this->maxResultsParameterName] ?? null;
        $searchterm = $context['filters'][$this->searchParameterName] ?? false;
        if ($searchterm !== false) {
            $aggregationBuilder->match()->field('id')->in($this->getFilteredIds($searchterm, null, null, $maxResults));
        }
    }

    public function getDescription(string $resourceClass): array
    {
        return [];
    }
}

这个解决方案可能不如使用api_platform本机提供的ElasticSearch-Connector那么优雅,但它的性能相当高,而且可以正常工作。
但是,如果有人提出解决方案来修复api_platform的ES-Connector问题,请随时与我们分享。

z2acfund

z2acfund2#

问题是,FOS Elastica需要一个带斜杠结尾的ES URL,而Api Platform需要一个不带斜杠结尾的URL。
我们通常在.env文件中定义URL,然后在配置文件中调用它。为了解决这个问题,我们可以在.env文件中定义URL,不使用斜杠结尾,然后将斜杠添加到FOS Elastica配置文件中。
第一个

相关问题