При reindex не получается преобразовать поле в nested

Хочу чтобы одно поле стало вместо простого текста nested объектом с этим же текстом. Маппинг нового поля:

{
  "nested-2017-13" : {
    "mappings" : {
      "searchtype" : {
        "properties" : {
          "body2" : {
            "type" : "nested",
            "dynamic" : "strict",
            "properties" : {
              "text2" : {
                "type" : "text",
                "fields" : {
                  "original" : {
                    "type" : "text",
                    "analyzer" : "body_analyzer_original"
                  }
                },
                "analyzer" : "body_analyzer_with_hunspell",
                "search_analyzer" : "search_analyzer"
              }
            }
          }
        }
      }
    }
  }
}

Пытаюсь сделать reindex и скриптом присвоить то же содержимое... не выходит.

{
 "conflicts": "proceed",
  "source": {
    "index": "doc-2017-03-hs-67",
    "size": "1000"
  },
  "dest": {
    "index": "nested-2017-13",
    "version_type": "external"
  },
  "script": {
    "source": "ctx._source.body2.text2=ctx._source.remove('body') ",
    "lang": "painless"
  }
}

Перепровал кучу вариантов. Ругается по разному, но как-то не вразумительно.

"script_stack" : [
  "ctx._source.body2.text2=ctx._source.remove('body') ",
  "                 ^---- HERE"
],
"script" : "ctx._source.body2.text2=ctx._source.remove('body') ",
"lang" : "painless",
"caused_by" : {
  "type" : "null_pointer_exception",
  "reason" : null
}

У вас скорее всего body2 нет в документе. Часть ctx._source.body2 пытается получить body2 его нет, она возвращает null на котором вы вызываете text2 и получаете ошибку.

body2 в новом индексе, его естественно нет.
А вот body в старом индексе пустые в первых документах при переиндексации.
Видимо так и получается.
Сейчас попробую. Спасибо.

Не работает.
В старом документе действительно нет body2, совсем.
Но я его присваиваю, а не получаю.

Что не работает? Я пробовал так:

DELETE test

PUT test/_doc/1
{
  "body": "foo"
}

POST _reindex
{
 "conflicts": "proceed",
  "source": {
    "index": "test",
    "size": "1000"
  },
  "dest": {
    "index": "test2",
    "version_type": "external"
  },
  "script": {
    "source": "ctx._source.body2 = new HashMap(); ctx._source.body2.text2=ctx._source.remove('body') ",
    "lang": "painless"
  }
}

GET test2/_doc/1

Получаю

{
  "_index" : "test2",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "found" : true,
  "_source" : {
    "foo" : "bar",
    "body2" : {
      "text2" : "foo"
    }
  }
}

Да, так работает! Странно, что нужно создать поле самостоятельно ведь обычное поле создается само. Спасибо!

Ну давайте разбираться. Когда у вас структура выглядит так: map.field = val то это транслируется в map.put("field", val). Если поле с именем field уже есть - оно переписывается, если нет - создается.

Однако, если у вас val = map.field, то это транслируется в val = map.get("field").

Теперь давайте рассмотрим, что происходит с map.foo.bar = val. В этом случае для bar применяется то же правило, что и в первом случае, потому что он стоит слева от присвоения, а для foo применяется второе правило, потому что он используется, чтобы получить доступ к bar.

Другими словами, это транслируется в map.get("foo").set("bar", val). Если в map элемента с именем foo нет, то map.get("foo") возвращает null, и все это превращается в null.set("bar", val).

1 Like

Ясно, но непонятно :slight_smile:
Почему не транслировать map.field1.field2=val в map.put([field1,field2],val) ?

Потому что в Java map.put([field1,field2],val) нет.

Ну это условно говоря. Ладно. Тема более чем раскрыта. Спасибо за такое объяснение.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.