Data Views

Data views (formerly index patterns) tell Kibana which Elasticsearch indices, data streams, and aliases to query. kibana-py exposes the full Data Views API as client.data_views: data view CRUD, runtime field management, field metadata, the default data view, and saved-object reference swapping.

Creating Data Views

A data view needs a title — a comma-separated list of index patterns to search:

from kibana import Kibana

client = Kibana("http://localhost:5601", api_key="your_api_key")

response = client.data_views.create(
    data_view={
        "title": "my-logs-*",
        "name": "My Logs",
        "timeFieldName": "@timestamp",
    }
)

view_id = response.body["data_view"]["id"]
print(f"Created data view: {view_id}")

Optional data_view keys include id (choose your own), allowNoIndex, fieldFormats, runtimeFieldMap, sourceFilters, namespaces, type, and typeMeta. Pass override=True to replace an existing data view with the same title.

Note

Creating the first data view in a space implicitly makes it the default data view for that space (an undocumented Kibana behavior).

Reading, Listing, Updating, Deleting

# List all data views in the space (summary fields only)
views = client.data_views.get_all()
for view in views.body["data_view"]:
    print(view["id"], view["title"])

# Get one data view, including its fields
view = client.data_views.get(view_id=view_id)
print(view.body["data_view"]["title"])

# Partial update: only the provided properties change
client.data_views.update(
    view_id=view_id,
    data_view={"name": "Renamed view"},
    refresh_fields=True,   # reload fields after the update
)

# Delete (cannot be recovered)
client.data_views.delete(view_id=view_id)

Tip

Unlike the tech-preview Dashboards API, data_views.update() is a partial update — omitted properties keep their current values.

Runtime Fields

Runtime fields are computed at query time from a Painless script — no reindexing required. kibana-py covers the full runtime field lifecycle:

# Create a runtime field
client.data_views.create_runtime_field(
    view_id=view_id,
    name="hour_of_day",
    runtime_field={
        "type": "long",
        "script": {
            "source": "emit(doc['@timestamp'].value.getHour())"
        },
    },
)

# Read it back
field = client.data_views.get_runtime_field(view_id=view_id, name="hour_of_day")

# Update the script
client.data_views.update_runtime_field(
    view_id=view_id,
    name="hour_of_day",
    runtime_field={
        "script": {
            "source": "emit(doc['@timestamp'].value.getHour() + 1)"
        },
    },
)

# Upsert (create or replace)
client.data_views.create_or_update_runtime_field(
    view_id=view_id,
    name="day_of_week",
    runtime_field={
        "type": "keyword",
        "script": {
            "source": "emit(doc['@timestamp'].value.getDayOfWeekEnum().toString())"
        },
    },
)

# Delete
client.data_views.delete_runtime_field(view_id=view_id, name="hour_of_day")

Runtime field responses include both the affected fields and the updated data_view object.

Field Metadata

Customize how fields are presented in Kibana (labels, descriptions, popularity, formats):

client.data_views.update_fields_metadata(
    view_id=view_id,
    fields={
        "response_code": {"customLabel": "Status"},
        "bytes": {"count": 5},  # boost popularity in field lists
    },
)

Note

The 9.4.3 API spec documents the response as {"acknowledged": true}, but the live server returns the full updated data_view object.

The Default Data View

# Get the default data view ID for the space
default = client.data_views.get_default()
print(default.body["data_view_id"])

# Set the default (force=True overrides an existing default)
client.data_views.set_default(data_view_id=view_id, force=True)

Note

When no default is set, the live server returns {"data_view_id": ""} (an empty string). Also, the stored default is not validated — it can point at an already-deleted data view.

Swapping Saved Object References

When replacing one data view with another (for example after a migration), you can rewrite references in saved objects that point at the old view:

# Preview what would change (no writes)
preview = client.data_views.preview_swap_references(
    from_id="old-view-id",
    to_id="new-view-id",
)
print(preview.body["result"])

# Perform the swap, optionally deleting the old data view afterwards
client.data_views.swap_references(
    from_id="old-view-id",
    to_id="new-view-id",
    delete=True,
)

Both methods accept optional filters: from_type, for_id, and for_type limit which referencing objects are rewritten.

Space-Scoped Data Views

All operations accept space_id, or use a space-scoped client:

response = client.data_views.create(
    data_view={"title": "marketing-*", "timeFieldName": "@timestamp"},
    space_id="marketing",
)

marketing = client.space("marketing")
views = marketing.data_views.get_all()

Complete Example

from kibana import Kibana
from kibana.exceptions import NotFoundError

with Kibana("http://localhost:5601", api_key="your_api_key") as client:
    created = client.data_views.create(
        data_view={
            "title": "kbnpy-demo-*",
            "name": "kibana-py demo",
            "timeFieldName": "@timestamp",
            "allowNoIndex": True,   # OK if no matching index exists yet
        }
    )
    view_id = created.body["data_view"]["id"]

    try:
        client.data_views.create_runtime_field(
            view_id=view_id,
            name="hour_of_day",
            runtime_field={
                "type": "long",
                "script": {"source": "emit(doc['@timestamp'].value.getHour())"},
            },
        )

        view = client.data_views.get(view_id=view_id)
        print(f"{view.body['data_view']['name']}: "
              f"{len(view.body['data_view'].get('fields', {}))} fields")
    finally:
        try:
            client.data_views.delete(view_id=view_id)
        except NotFoundError:
            pass

Next Steps

  • Build Dashboards on top of your data views

  • Manage data views across Spaces

  • Browse examples/data_views_management.py in the repository for a runnable end-to-end script