elastic / elasticsearch-java

Official Elasticsearch Java Client
Apache License 2.0
397 stars 228 forks source link

Cannot parse DynamicTemplate mapping with unknown field #810

Closed ahermes closed 1 month ago

ahermes commented 2 months ago

Java API client version

7.17.21

Java version

17

Elasticsearch Version

7.16.2

Problem description

When i try to put a mapping to an already created indice with these settings

{
  "max_ngram_diff": 50,
  "analysis": {
    "tokenizer": {
      "ngram_tokenizer_3-20": {
        "type": "ngram",
        "min_gram": 3,
        "max_gram": 20,
        "token_chars": [
          "letter",
          "digit",
          "punctuation",
          "symbol"
        ]
      }
    },
    "analyzer": {
      "designation_analyser": {
        "type": "custom",
        "tokenizer": "ngram_tokenizer_3-20",
        "filter": [
          "lowercase",
          "asciifolding"
        ]
      }
    }
  }
}

I use a dynamic_template with an analyzer

{
  "properties": {
    "id": {
      "type": "keyword"
    },
    "code": {
      "type": "keyword"
    },
    "forbidden": {
      "type": "boolean"
    },
    "designations": {
      "type": "object",
      "dynamic": true
    },
    "keyWords": {
      "type": "nested",
      "properties": {
        "id": {
          "type": "keyword"
        },
        "label": {
          "type": "keyword"
        }
      }
    }
  },
  "dynamic_templates": [
    {
      "designations": {
        "match_mapping_type": "string",
        "match": "([a-z]{2}_[A-Z]{2})",
        "mapping": {
          "type": "keyword",
          "index": "analyzed",
          "analyzer": "designation_analyser",
          "path_match": "designations.*"
        }
      }
    }
  ]
}

which result in a JsonpMappingException for fields "analyzer" and "path_match" in the "mapping" section Error deserializing co.elastic.clients.elasticsearch._types.mapping.KeywordProperty: Unknown field 'analyzer' (JSON path: dynamic_templates[0].designations.mapping.analyzer)

it is demonstrated in the documentation that it is usable that way. (indices created without any problem with this json with the java-high-level-api)

The way i send the request :

final RestClient httpClient = RestClient.builder(esHostList.stream()
                .map(esHost -> new HttpHost(esHost, esPort, httpProtocol))
                .toArray(HttpHost[]::new))
                .build();
final ElasticsearchTransport transport = new RestClientTransport(httpClient, jacksonMapper);
final ElasticsearchClient client = new ElasticsearchClient(transport);

final PutMappingRequest.Builder request = new PutMappingRequest.Builder()
                .index(indexName)
                .withJson(new ByteArrayInputStream(mappingAsJson.getBytes(StandardCharsets.UTF_8)));
client.indices().putMapping(request.build());
l-trotta commented 2 months ago

Hello, I think you're using the wrong mapping type here. The documentation shows that analyzer is used with a text type mapping, while you're using keyword which doesn't support analyzer.

ahermes commented 2 months ago

Hello, thanks for your answer, but I'm unsure this is the case as it worked previously and the indice was created using this same mapping with the old API. Could you please send the source regarding the keyword not supporting analyzer ?

l-trotta commented 1 month ago

I was comparing the documentation for keyword and text and seeing the analyzer explicitly mentioned only in text, but you're right it works with keyword too, so the documentation is probably missing it. We'll investigate and correct both client and documentation, thank you for the report!

l-trotta commented 1 month ago

Hello again! I have checked the server code thoroughly, I am now sure that keyword does not support analyzer. It's not in the list of parameters, whereas text has it (it's called indexAnalyzer but the actual name is analyzer as shown here). The fact that the dynamic template creation works is because mapping in dynamic_templates is a Map that accepts anything, for example can I successfully create and retrieve something like this: image and it works ^^" . Another way to prove it is to try with a simple mapper (without dynamic template), and see that this is accepted:

PUT text_test
{
  "mappings": {
    "properties": {
      "tags": {
        "type":  "text",
        "analyzer": "standard"
      }
    }
  }
}

while this returns unknown parameter [analyzer] on mapper [tags] of type [keyword]:

PUT keyword_test
{
  "mappings": {
    "properties": {
      "tags": {
        "type":  "keyword",
        "analyzer": "standard"
      }
    }
  }
}

I hope this clear things up!

ahermes commented 1 month ago

Hello , Yes ! It is clearer. I followed your advice and modified my mapping, everything is working on my end.

Thanks again for your time ! 🙏