Master Elasticsearch Composite Field Types: Array, Flattened, and Nested Best Practices

This guide explains Elasticsearch's mapping concepts, compares dynamic and static mappings, and demonstrates how to choose between Array, Flattened, and Nested field types with concrete code examples, performance trade‑offs, and practical recommendations for real‑world business systems.

Shepherd Advanced Notes
Shepherd Advanced Notes
Shepherd Advanced Notes
Master Elasticsearch Composite Field Types: Array, Flattened, and Nested Best Practices

Overview

Elasticsearch is a distributed, real‑time search and analytics engine built on Apache Lucene. It is commonly used for log analysis, monitoring, and large‑scale data retrieval.

Mapping

Mapping defines the structure, type, and indexing behavior of fields in an index, similar to a table schema in a relational database.

Dynamic Mapping

Elasticsearch automatically creates field definitions based on the first document inserted.

PUT user_info
PUT user_info/_doc/1
{
  "id": 1,
  "name": "张三",
  "amount": 88.99
}

Retrieving the mapping shows:

{
  "user_info": {
    "mappings": {
      "properties": {
        "amount": {"type": "float"},
        "id": {"type": "long"},
        "name": {
          "type": "text",
          "fields": {"keyword": {"type": "keyword", "ignore_above": 256}}
        }
      }
    }
  }
}

Elasticsearch detected the field types and created the mapping automatically.

Static Mapping

Fields can be defined before any document is indexed.

PUT user_info/_mapping
{
  "properties": {
    "idCard": {"type": "keyword"}
  }
}

The keyword type stores the value without analysis, suitable for exact match and aggregation. When a text field is defined, Elasticsearch also creates a keyword sub‑field (e.g., name.keyword) to support exact matching.

Example of a combined text + keyword definition:

"idCard": {
  "type": "text",
  "fields": {
    "keyword": {"type": "keyword", "ignore_above": 256}
  }
}

The ignore_above: 256 setting prevents indexing values longer than 256 characters.

Array for One‑to‑Many Queries

Any field can store an array implicitly, provided all elements share the same type.

PUT user_info/_mapping
{
  "properties": {"tag": {"type": "long"}}
}

Insert documents with multiple tag IDs:

PUT user_info/_doc/10
{ "id": 10, "name": "张三2", "tag": [1,2,3] }

PUT user_info/_doc/11
{ "id": 11, "name": "张三3", "tag": [3,4] }

PUT user_info/_doc/12
{ "id": 12, "name": "张三4", "tag": [4,8,9] }

PUT user_info/_doc/13
{ "id": 13, "name": "张三5", "tag": [1,6] }

Query for users whose tag contains 3 or 4:

GET user_info/_search
{
  "query": {"terms": {"tag": [3,4]}}
}

Result: documents with id 10, 11, 12.

boolQueryBuilder.must(QueryBuilders.termsQuery("tag", tagIds));

Limitation: arrays cannot express relationships between elements. Example where correlation is required cannot be expressed:

PUT orders/_doc/1
{ "products": ["laptop","mouse"], "quantities": [1,2] }

Querying for a product and its specific quantity is not possible with plain arrays; a nested type is required.

Flattened Type for Dynamic Key‑Value Data

Introduced in Elasticsearch 7.3, the flattened type stores hierarchical JSON objects as a single‑level field, reducing memory usage and improving query speed for dynamic key‑value pairs.

PUT user_info/_mapping
{
  "properties": {"extendInfo": {"type": "flattened"}}
}

Update documents with varying sub‑fields:

POST user_info/_update/10
{ "doc": {"extendInfo": {"age":18, "gender":"女", "height":180, "weight":"68kg"}}}

POST user_info/_update/11
{ "doc": {"extendInfo": {"age":30, "gender":"女"}}}

POST user_info/_update/12
{ "doc": {"extendInfo": {"height":170, "weight":"58kg", "hobby":"篮球"}}}

POST user_info/_update/13
{ "doc": {"extendInfo": {"address":"杭州", "phone":"12334464"}}}

Query for gender = "女" and age = 18:

GET user_info/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"extendInfo.gender": {"value": "女"}}},
        {"term": {"extendInfo.age": {"value": 18}}}
      ]
    }
  }
}

Result: document with id 10.

Flattened fields cannot participate in deep nested relationship queries.

Nested Type for Structured Object Arrays

The nested type stores each array element as an independent hidden document, preserving intra‑object relationships.

PUT user_info/_mapping
{
  "properties": {"family": {"type": "nested"}}
}

Insert family members for several users:

POST user_info/_update/10
{ "doc": {"family": [
    {"name":"李四", "relation":"父子", "amount":10000},
    {"name":"王婆", "relation":"母子", "amount":6000}
]}}

POST user_info/_update/11
{ "doc": {"family": [
    {"name":"李四", "relation":"兄弟", "amount":10000},
    {"name":"小红", "relation":"夫妻", "amount":1000}
]}}

POST user_info/_update/12
{ "doc": {"family": [
    {"name":"王五", "relation":"父子", "amount":10000},
    {"name":"小兰", "relation":"兄妹", "amount":1000}
]}}

Query for family members where relation is "父子" and amount is 10000:

GET user_info/_search
{
  "query": {
    "nested": {
      "path": "family",
      "query": {
        "bool": {
          "must": [
            {"term": {"family.relation.keyword": {"value": "父子"}}},
            {"term": {"family.amount": {"value": 10000}}}
          ]
        }
      }
    }
  }
}

Result: documents with id 10 and id 12.

Nested objects are indexed as separate hidden documents, which increases storage and query cost. Partial updates of a nested object require rewriting the entire nested array.

Comparison

Array : Simple multi‑value fields (e.g., tags, interests). Easy to use and performant, but cannot maintain relationships between elements.

Flattened : Dynamic key‑value structures (e.g., configurable metadata, logs). Low storage overhead and good for dynamic fields, but does not support deep nested relationship queries.

Nested : Multi‑level object arrays requiring intra‑object queries (e.g., family relationships). Supports complex relationship queries, at the cost of higher storage and query overhead.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendElasticsearchMappingArrayNestedFlattened
Shepherd Advanced Notes
Written by

Shepherd Advanced Notes

Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.