# Dynamic template mapping overridden by automatic \`dense\_vector\` inference for float arrays

**URL:** <https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359>\
**Category:** Elasticsearch\
**Tags:** vector-search\
**Created:** [March 6, 2026, 7:49am UTC](https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359 "2026-03-06T07:49:54Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![giga811](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/giga811/32/26499_2.png) [@giga811](https://discuss.elastic.co/u/giga811)\
**Post date:** [March 6, 2026, 7:49am UTC](https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359/1 "2026-03-06T07:49:54Z")

</div>

I encountered a situation where a dynamic template specifying a field as `float` is overridden by automatic `dense_vector` mapping when indexing a long float array in Elasticsearch.

My intention is to store embeddings as a plain float array (not as a vector field), but Elasticsearch automatically converts the field to `dense_vector`, ignoring the dynamic template.

According to the [document](https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector?utm_source=chatgpt.com#index-vectors-knn-search), unmapped long array would become vector, but here I already applied the dynamic\_template.

> Unmapped array fields of float elements with size between 128 and 4096 are dynamically mapped as `dense_vector`

### Example

On Elasticsearch 9.2.4

Create an index with a dynamic template:

```auto
PUT test_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "embedding_as_float": {
          "path_match": "*.embedding",
          "mapping": {
            "type": "float",
            "index": false
          }
        }
      }
    ]
  }
}

```

Index a document:

```auto
POST test_index/_doc
{
  "text_embedding": {
    "embedding": [
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,
      0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0
    ]
  }
}

```

Mapping result:

The `text_embedding.embedding` field has become `dense_vector` despite the dynamic mapping.

```auto
GET test_index/_mapping

```

```auto
{
  "test_index": {
    "mappings": {
      "dynamic_templates": [
        {
          "embedding_as_float": {
            "path_match": "*.embedding",
            "mapping": {
              "index": false,
              "type": "float"
            }
          }
        }
      ],
      "properties": {
        "text_embedding": {
          "properties": {
            "embedding": {
              "type": "dense_vector",
              "dims": 150,
              "index": true,
              "similarity": "cosine",
              "index_options": {
                "type": "int8_hnsw",
                "m": 16,
                "ef_construction": 100
              }
            }
          }
        }
      }
    }
  }
}

```

### Additional observations

- The dynamic template appears to work if the array is very short, but once the float array becomes longer it is automatically mapped as `dense_vector`.

- If I change the dynamic template type to `integer`, the template works and the field is not converted to a vector. So the `path_match` is working as intended

- When `index: false` is specified in the template, the automatically created `dense_vector` mapping ignores this and sets `index: true`.

### Why I want this behavior

I store embeddings for two different purposes:

- One field is used for kNN search (so `dense_vector` is appropriate).

- Another field is only for storing the raw embedding for later retrieval.

Because of [the vector changes in newer versions of Elasticsearch](https://www.elastic.co/search-labs/blog/elasticsearch-exclude-vectors-from-source), vector fields are excluded from `_source` by default unless `"exclude_vectors": false` is specified in queries. I would prefer to store this field simply as a float array (`index: false`) rather than a `dense_vector`.

### Question

Is this behavior expected (automatic vector inference overriding dynamic templates), or is there a recommended way to disable vector auto-detection so that the dynamic template mapping is respected?

---

<div class="post-metadata">

**Author:** ![giga811](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/giga811/32/26499_2.png) [@giga811](https://discuss.elastic.co/u/giga811)\
**Post date:** [March 6, 2026, 11:15am UTC](https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359/2 "2026-03-06T11:15:57Z")

</div>

I found potential root cause and raised issue in github.

> <https://github.com/elastic/elasticsearch/issues/143732>
>
> \### Elasticsearch Version
> 
> 9.2.4
> 
> \### Installed Plugins
> 
> \_No response\_
> 
> \### Java… Version
> 
> \_bundled\_
> 
> \### OS Version
> 
> n/a
> 
> \### Problem Description
> 
> \## Summary
> 
> I encountered an issue where dynamic templates are being overridden by the automatic dense\_vector mapping feature. When I index a float array with 128-4096 elements on a nested field, my dynamic template is completely ignored, and the field gets converted to \`dense\_vector\` instead.
> 
> \*\*Affects\*\*: Elasticsearch 8.11.0+ (tested on 9.2.4)
> 
> \## What I Found
> 
> After digging into the code, I found there's a field name mismatch in the tracking logic:
> 
> \- When a dynamic template is applied (\`DynamicFieldsBuilder.java:210\`), the field is marked using the \*\*short name\*\* (e.g., \`"embedding"\`)
> - https://github.com/elastic/elasticsearch/blob/cc5852ba70cc49a07ac338e69d1a90c2478b6937/server/src/main/java/org/elasticsearch/index/mapper/DynamicFieldsBuilder.java#L210
> \- Later, when checking if a template was applied (\`DocumentParser.java:823\` in \`postProcessDynamicArrayMapping\`), it checks using the \*\*full path\*\* (e.g., \`"text\_embedding.embedding"\`)
> - https://github.com/elastic/elasticsearch/blob/cc5852ba70cc49a07ac338e69d1a90c2478b6937/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java#L823
> \- Since \`"embedding"\` != \`"text\_embedding.embedding"\`, the check fails and the automatic dense\_vector conversion kicks in
> 
> The check \`context.isFieldAppliedFromTemplate(fullFieldName)\` is there to prevent this exact scenario, but it doesn't work due to the name mismatch.
> 
> It was introduced in PR #98512 ("Automatically map floats as dense vector"). If you read the PR along with this, it would be easier to track.
> 
> \## Additional Notes
> 
> \- Using \`match\` instead of \`path\_match\` has the same issue for nested fields
> \- Changing template type to \`integer\` works (template is respected), so I can confirm that the template matching itself is working
> \- Top-level fields with simple \`match\` patterns work fine
> 
> \## Related
> 
> This is an issue from elastic forum report https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359
> 
> 
> \### Steps to Reproduce
> 
> 
> \## Reproduction
> 
> Here's a minimal example:
> 
> \*\*1. Create index with dynamic template:\*\*
> \`\`\`json
> PUT test\_index
> {
> "mappings": {
> "dynamic\_templates": \[
> {
> "embedding\_as\_float": {
> "path\_match": "\*.embedding",
> "mapping": {
> "type": "float",
> "index": false
> }
> }
> }
> \]
> }
> }
> \`\`\`
> 
> \*\*2. Index a document with 150-element float array:\*\*
> \`\`\`json
> POST test\_index/\_doc
> {
> "text\_embedding": {
> "embedding": \[
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0
> \]
> }
> }
> \`\`\`
> 
> \*\*3. Check the mapping:\*\*
> \`\`\`json
> GET test\_index/\_mapping
> \>\>\>output
> {
> "test\_index": {
> "mappings": {
> "dynamic\_templates": \[
> {
> "embedding\_as\_float": {
> "path\_match": "\*.embedding",
> "mapping": {
> "index": false,
> "type": "float"
> }
> }
> }
> \],
> "properties": {
> "text\_embedding": {
> "properties": {
> "embedding": {
> "type": "dense\_vector",
> "dims": 150,
> "index": true,
> "similarity": "cosine",
> "index\_options": {
> "type": "int8\_hnsw",
> "m": 16,
> "ef\_construction": 100
> }
> }
> }
> }
> }
> }
> }
> }
> 
> 
> \`\`\`
> 
> \## Expected vs Actual
> 
> \*\*Expected\*\*: \`text\_embedding.embedding\` should be \`float\` with \`index: false\` per my template.
> 
> \*\*Actual\*\*: The field becomes \`dense\_vector\` with \`dims: 150\`, \`index: true\`, completely ignoring my template.
> 
> 
> \### Logs (if relevant)
> 
> \_No response\_

---

<div class="post-metadata">

**Author:** ![Carlos\_D](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/carlos_d/32/126245_2.png) [@Carlos\_D](https://discuss.elastic.co/u/Carlos_D)\
**Post date:** [March 6, 2026, 12:35pm UTC](https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359/3 "2026-03-06T12:35:16Z")

</div>

Hi @giga811 !

Thanks for opening the bug. I’ve checked the bug reproduced, thanks for taking the trouble on providing a minimal bug reproduction.

While we prioritize work on it, I Just wanted to check if you have a viable workaround.

If you want to keep the original value that was indexed as-is, you probably want \_source (as it already does that for you). If you really want to keep the original raw field, you can use `"index.mapping.exclude_source_vectors": true` in your index mapping, so you don’t need to specify that on the queries.

If you want to get the indexed value (not exactly what you introduced, but close enough), remember that you can use `fields` for retrieving the value even if you don’t store the \_source for it.

Hope that helps!

---

<div class="post-metadata">

**Author:** ![giga811](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/giga811/32/26499_2.png) [@giga811](https://discuss.elastic.co/u/giga811)\
**Post date:** [March 7, 2026, 6:16am UTC](https://discuss.elastic.co/t/dynamic-template-mapping-overridden-by-automatic-dense-vector-inference-for-float-arrays/385359/4 "2026-03-07T06:16:54Z")

</div>

Thank you the response.

Yes, we are currently using the `"index.mapping.exclude_source_vectors": true` option. One of our motivation was to stop using this option so that es index is optimized for the new way of storing and handling the vector. As we have actual vector fields for the vector search too.

I am thinking of alternative to dynamically mapping the field to `integer`, as we don’t really use the field for search so different type is fine for us. It is more important that it is marked as `index: false` for the field. I saw that even with `integer` type, the source retrieval returns the raw float numbers, so I think it will suffice our usecase.
