Эластичный поиск возвращает вложенный объект с ошибкой пути

#php #laravel #elasticsearch

Вопрос:

Вкратце, в Laravel я использую пакет elasticsearch_php. У меня есть несколько продуктов, которые индексируют их в эластичном поиске. Когда я хочу выполнить поиск в индексированных продуктах со строкой запроса, я получаю сообщение об ошибке:

[вложенный] вложенный объект по пути [категории] не имеет вложенного типа». Вот мой код.

У меня есть файл миграции CreateProductSearchIndex для эластичных индексов продукта, который выглядит следующим образом, и определяет тип категорий как nested

 public function up() {
        $this->elastic->indices()->create([
            'index' => 'product',
            'body' => [
                'mappings' => [
                    'properties' => [
                        'name' => [
                            'type' => 'text',
                            'analyzer' => 'persian'
                        ],
                        'slug' => [
                            'type' => 'keyword'
                        ],
                        //....
                        'categories' => [
                            'type' => 'nested',
                            'properties' => [
                                'id' => [
                                    'type' => 'long'
                                ],
                                'name' => [
                                    'type' => 'text',
                                    'analyzer' => 'persian'
                                ],
                                'parent_id' => [
                                    'type' => 'long'
                                ]
                            ]
                        ]
                    ]
                ]
            ]
        ]);
    }
 

В методе я передаю id продукт и индексирую продукт (добавляю его в elastic).

 public function sync(int $id, string $sync = SyncEvent::SYNC_ALL): void
{
    $product = $this->repository->product->find($id, false);
    if ($product) {
        $exists = $this->repository->search->exists(['id' => $product->id]);
        if (!$exists) {
            $this->elastic->index([
                'id' => $product->id,
                'body' => $this->getProduct($product, $sync),
            ]);
        } 
    }
    // ...
}

private function getProduct(Product $product, string $sync): array
{
    $data = [];
    if ($this->shouldSync($sync, ProductSyncEvent::SYNC_PRODUCT)) {
        $data = $product->toArray([
            'id', 'name', // ...
        ]);
        // ...
        $data['categories'] = $product->categoryHierarchy()->map->only(['id', 'name', 'parent_id'])->toArray();
    }
    return $data;
}
 

After indeces some products I can see them in elatic
result of getting product without query string

 curl -u '<username>:<password>' -X GET "http://localhost:9200/product/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 1000
}
'
 

is like this:

 {
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "175",
        "_score" : 1.0,
        "_source" : {
          "id" : 175,
          "name" : "first product",
          "categories" : [
            {
              "id" : 262,
              "name" : "cat1",
              "parent_id" : 251
            },
            {
              "id" : 251,
              "name" : "cat2",
              "parent_id" : 0
            }
          ]
        }
      }
    ]
  }
}

 

It seems everything is right. But when I send requet with query string like:

 curl -u '<username>:<password>' -X GET "http://localhost:9200/product/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 1000,
    "query": {
        "nested" : {
            "path" : "categories",
            "query" : {
                "bool" : {
                    "must" : [
                        { "match" : {"categories.name" : "cat1"} }
                    ]
                }
            }
        }
    }
}
'
 

Я получаю сообщение об ошибке, в котором говорится:

«причина»: «Не удалось создать запрос: [вложенный] вложенный объект по пути [категории] не имеет вложенного типа».

Здесь вы можете увидеть сопоставление данных:

 curl -u '<username>:<password>' http://localhost:9200/product/_mapping?pretty
 
 {
  "product": {
    "mappings": {
      "properties": {
        "categories": {
          "properties": {
            "id": {
              "type": "long"
            },
            "name": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "parent_id": {
              "type": "long"
            }
          }
        },
        "id": {
          "type": "long"
        },
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}
 

Я не знаю, что не так с моим кодом. Любая помощь-это любая помощь, которая ценится.

Комментарии:

1. перейдите на свой ES-сервер, например localhost:9200/product , чтобы проверить, правильно ли свойство создано как вложенное. Если это не так, попробуйте удалить и воссоздать индекс

2. @apokryfos Я переиндексирую его снова и снова. Кроме того, я подумал, что, возможно, есть проблема с данными. поэтому я отбрасываю все продукты и индексирую только один.

3. отбросьте весь индекс. Если вы удалите все продукты, сопоставление все еще будет сохранено

4. @apokryfos Я использую это: curl -u '<u>:<pass>' http://localhost:9200/product -XDELETE . Я прав?

5. Да, это снизило бы индекс. Затем после этого убедитесь, что миграция выполняется, прежде чем добавлять какие-либо документы, иначе индекс будет автоматически изменен