Understanding the Data View Feature in INFINI Console for Elasticsearch Time-Series Analysis
The Data View feature (also called index-pattern in the UI) is a logical configuration that groups Elasticsearch indices, designates a time-filter field for time-series queries, and maps custom formatters to specific fields so raw values display as human-readable strings like "0.5 GB" instead of bytes.
The data view feature sits at the heart of the INFINI Console (infinilabs/console) open-source project, acting as the bridge between raw Elasticsearch indices and user-friendly visualizations. By storing view definitions as documents in a system Elasticsearch cluster, the console enables consistent, reusable configurations for time-series exploration across any index pattern.
What Is the Data View Feature?
A Data View is a persisted JSON document that defines which Elasticsearch indices belong together and how the console should interpret their fields. Stored in the system cluster using the template at config/setup/common/view.tpl, each view contains:
title: The index pattern (e.g.,logs-*ormetrics-2024.*)viewName: A human-readable identifiertimeFieldName: The field used for time-range filtering (e.g.,@timestamp)fields: An array of field metadatafieldFormatMap: A mapping of field names to formatter configurations
According to the source code in config/setup/common/view.tpl (lines 5-9), the template explicitly defines timeFieldName and fieldFormatMap as core properties when a view is indexed via PUT $[[SETUP_INDEX_PREFIX]]view/.
How Data Views Support Time-Series Field Formatting
Time-series data in Elasticsearch often contains raw metrics—bytes, milliseconds, or ratios—that are unreadable without formatting. The data view feature solves this through two complementary mechanisms.
Defining the Time Filter Field
The timeFieldName property designates which field serves as the global time filter. When a user selects a time range in the UI, visualization components retrieve the data view, extract timeFieldName, and construct Elasticsearch range queries targeting that specific field. This ensures all panels in a dashboard respect the same temporal boundary.
Mapping Field Formatters
The fieldFormatMap is a JSON object where each key is a fully-qualified field name and each value specifies an id (formatter type) and optional params. For example:
{
"system.memory.used.bytes": {
"id": "bytes",
"params": {}
},
"cpu.usage": {
"id": "percent",
"params": {"pattern": "0.00%"}
}
}
When rendering charts or tables, the console looks up each metric field in fieldFormatMap and invokes the corresponding formatter implementation from web/src/utils/format.js.
Technical Implementation in the Codebase
The data view feature spans the backend storage layer, REST API, and frontend formatting utilities.
Data View Storage Template
The structural definition resides in config/setup/common/view.tpl. This template is used during setup to create the mapping and initial documents in the system index. Lines 5-9 establish the schema for timeFieldName and fieldFormatMap, ensuring these fields are indexed and searchable when views are persisted.
API Layer for Data Retrieval
The HTTP handlers in modules/elastic/api/view.go serve data view definitions to the frontend. The functions HandleGetViewListAction and HandleGetViewAction (lines 337-339) extract the fieldFormatMap from the stored document and return it verbatim in the JSON response:
// Simplified representation of the API response structure
response := map[string]interface{}{
"view": map[string]interface{}{
"title": view.Title,
"timeFieldName": view.TimeFieldName,
"fieldFormatMap": view.FieldFormatMap, // Returned as-is for frontend use
},
}
This ensures the UI receives the exact formatter configuration needed to render values correctly.
Formatter Utilities
The actual transformation logic lives in web/src/utils/format.js. The formatter.bytes function (lines 9-21) converts raw byte integers into human-readable strings:
// From web/src/utils/format.js
export const formatter = {
bytes: (value) => {
if (value === null || value === undefined) return '-';
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (value === 0) return '0 Bytes';
const i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
return Math.round(value / Math.pow(1024, i), 2) + ' ' + sizes[i];
}
};
When a visualization component detects that a field has id: "bytes" in the fieldFormatMap, it routes the raw Elasticsearch value through this function before rendering.
End-to-End Workflow
The data view feature operates through a five-stage pipeline:
-
Creation: The user submits a
POSTrequest to the view API withtitle,timeFieldName, and optionalfieldFormatMap. The backend usesconfig/setup/common/view.tplto index this document into the system cluster. -
Storage: The view persists in the system index with the mapping defined in the template, ensuring
timeFieldNameandfieldFormatMapare preserved as structured JSON. -
Retrieval: When loading a dashboard or discovery screen, the frontend calls
HandleGetViewAction(lines 337-339 inmodules/elastic/api/view.go), which returns the complete view definition including the formatter map. -
Query Construction: Visualization components extract
timeFieldNameto build Elasticsearchrangequeries that respect the global time picker, ensuring all panels query the same temporal window. -
Rendering: As results arrive, the UI checks
fieldFormatMapfor each metric field. If a formatter is defined (e.g.,id: "bytes"), the raw value passes through the corresponding function inweb/src/utils/format.jsbefore display.
Summary
- The data view feature (index-pattern) is a persisted configuration that groups Elasticsearch indices and defines time-series behavior.
- It stores
timeFieldNameto enable global time filtering across all visualizations. - The
fieldFormatMapproperty maps specific fields to formatter implementations (bytes, percent, number) for human-readable display. - View definitions reside in the system cluster using the schema defined in
config/setup/common/view.tpl. - The API layer in
modules/elastic/api/view.goserves these definitions to the frontend, which applies formatters fromweb/src/utils/format.jsat render time.
Frequently Asked Questions
What is the difference between a data view and an index pattern in INFINI Console?
Data view and index pattern refer to the same feature. The codebase and API use "data view" as the canonical term, while the UI and locale files (such as web/src/locales/en-US/explore.js) often display "index-pattern" to users familiar with Kibana terminology. Both terms describe the logical grouping of indices and their associated formatting rules.
How does the console know which formatter to apply to a specific field?
When rendering results, the console looks up the field name in the fieldFormatMap stored within the data view definition. If an entry exists, the id property (e.g., "bytes", "number", or "percent") determines which function to invoke from web/src/utils/format.js. The raw Elasticsearch value is then passed through that formatter function before being displayed in charts or tables.
Can I use wildcards when defining a data view title?
Yes. The title property in a data view supports wildcard patterns such as logs-* or metrics-2024.*. This allows a single data view to match multiple indices that share a common naming convention. The UI explicitly mentions this capability in the Create View dialog, as documented in the locale file web/src/locales/en-US/explore.js, enabling users to aggregate data across time-series indices without creating separate views for each index.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →