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

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

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

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

我的api_platform.yaml的内容如下:

  1. api_platform:
  2. [...]
  3. elasticsearch:
  4. hosts: [ '%env(ELASTICSEARCH_URL)%' ]
  5. mapping:
  6. App\Document\Post:
  7. index: posts

还有我的fos_elastica.yaml:

  1. fos_elastica:
  2. clients:
  3. default: { url: '%env(ELASTICSEARCH_URL)%' }
  4. indexes:
  5. posts:
  6. properties:
  7. id:
  8. "type": "keyword"
  9. source: ~
  10. title: ~
  11. description: ~
  12. body: ~
  13. children: ~
  14. tags: ~
  15. originalContent: ~
  16. persistence:
  17. driver: mongodb
  18. model: App\Document\Post

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

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

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

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

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

  1. #! Deprecation: [types removal] Specifying types in search requests is deprecated.
  2. {
  3. "took" : 12,
  4. "timed_out" : false,
  5. "_shards" : {
  6. "total" : 1,
  7. "successful" : 1,
  8. "skipped" : 0,
  9. "failed" : 0
  10. },
  11. "hits" : {
  12. "total" : {
  13. "value" : 3082,
  14. "relation" : "eq"
  15. },
  16. "max_score" : null,
  17. "hits" : [
  18. {
  19. "_index" : "posts",
  20. "_type" : "_doc",
  21. [...]

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

jdzmm42g

jdzmm42g1#

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

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

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

  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Filter;
  4. use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Filter\FilterInterface;
  5. use Doctrine\ODM\MongoDB\Aggregation\Builder;
  6. use Elastica\Result;
  7. use Elastica\Client;
  8. use Elastica\Query;
  9. use Symfony\Component\PropertyInfo\Type;
  10. /**
  11. * Filter the collection by given properties.
  12. *
  13. */
  14. final class FulltextFilter implements FilterInterface
  15. {
  16. protected $index = '';
  17. protected $properties = [];
  18. protected $client;
  19. protected $searchParameterName;
  20. protected $maxResultsParameterName;
  21. const DEFAULT_MAX_RESULTS = 200;
  22. public function __construct(Client $client, string $index = '', string $maxResultsParameterName = 'amount', string $searchParameterName = 'query', array $properties = []) {
  23. $this->index = $index;
  24. $this->properties = $properties;
  25. $this->client = $client;
  26. $this->searchParameterName = $searchParameterName;
  27. $this->maxResultsParameterName = $maxResultsParameterName;
  28. }
  29. public function getFilteredIds($searchterm, $index = null, $properties = null, $maxResults = null) {
  30. $matches = [];
  31. if (is_null($properties)) {
  32. $properties = array_keys($this->properties);
  33. }
  34. foreach ($properties as $propertyName) {
  35. array_push($matches, ['match'=>[$propertyName => $searchterm]]);
  36. }
  37. $queryObject = ['query' => ['bool' => ['should' => $matches]]];
  38. $queryObject['size'] = (int) $maxResults >0 ? (int) $maxResults : self::DEFAULT_MAX_RESULTS;
  39. $query = new Query();
  40. $response = $this->client->getIndex($index ?? $this->index)
  41. ->search($query->setRawQuery($queryObject))
  42. ->getResults();
  43. return array_map(function(Result $result) {return $result->getHit()['_source']['id'];}, $response);
  44. }
  45. public function apply(Builder $aggregationBuilder, string $resourceClass, string $operationName = null, array &$context = [])
  46. {
  47. $maxResults = $context['filters'][$this->maxResultsParameterName] ?? null;
  48. $searchterm = $context['filters'][$this->searchParameterName] ?? false;
  49. if ($searchterm !== false) {
  50. $aggregationBuilder->match()->field('id')->in($this->getFilteredIds($searchterm, null, null, $maxResults));
  51. }
  52. }
  53. public function getDescription(string $resourceClass): array
  54. {
  55. return [];
  56. }
  57. }

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

展开查看全部
z2acfund

z2acfund2#

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

相关问题