Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ jobs:
yarn cache clean
export NODE_OPTIONS=--max-old-space-size=8192
yarn
yarn key-features:generate

echo "Building with DOCS_VERSIONS=${DOCS_VERSIONS:-all}"
PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js yarn docusaurus build ${{ steps.detect.outputs.locale_args }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/cron-deploy-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
export NODE_OPTIONS=--max-old-space-size=8192
yarn
node ./scripts/update_github_info.js
yarn key-features:generate
PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js yarn docusaurus build --locale en --locale zh-CN
if [ ! -d "./ja-build" ]; then
echo "ja-build directory not found, aborting to avoid publishing incorrect ja content."
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/docs-next-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ jobs:
DOCS_VERSIONS: '4.x'
run: |
export NODE_OPTIONS=--max-old-space-size=8192
yarn key-features:generate
yarn docusaurus build --locale en --locale zh-CN

- name: Verify docs-next artifacts
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/manual-deploy-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
yarn cache clean
export NODE_OPTIONS=--max-old-space-size=8192
yarn
yarn key-features:generate
PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js yarn docusaurus build --locale en --locale zh-CN
if [ ! -d "./ja-build" ]; then
echo "ja-build directory not found, aborting to avoid publishing incorrect ja content."
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Generated files
.docusaurus
.cache-loader
/src/generated/key-features.ts

# Misc
.DS_Store
Expand Down
11 changes: 11 additions & 0 deletions docs-next/key-features/compute-storage-decoupled.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Compute-Storage Decoupled
description: Scale compute and storage independently with a decoupled Doris architecture.
slug: /key-features/compute-storage-decoupled
featureCard:
tags:
- cloud
- elastic
href: /docs-next/dev/compute-storage-decoupled/intro
---

21 changes: 21 additions & 0 deletions docs-next/key-features/high-availability.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: High Availability
description: Keep Doris available through replication, failover, and fault tolerance.
slug: /key-features/high-availability
featureCard:
tags:
- fault-tolerance
- replica
---

High availability is the set of mechanisms that help Doris stay online when nodes fail or need maintenance. Replication and failover are central to that behavior.

## When to use

Use this feature whenever the cluster must tolerate node loss or maintenance events without significant service interruption.

## Key points

- Replication protects data availability.
- Operational procedures matter as much as system design.
- Failover planning should be part of deployment planning.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
{
"title": "DML Plan Tuning: Locating Load and Query Performance Bottlenecks",
"sidebar_label": "DML Plan Tuning",
"language": "en",
"description": "How to tune Doris DML plans? This article explains how to distinguish between load and query bottlenecks, and provides entry points to best practices for both load and query tuning.",
"keywords": ["Doris DML tuning", "load performance bottleneck", "query performance bottleneck", "DML plan tuning", "Doris load best practices"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
{
"title": "DML 计划调优:定位导入与查询性能瓶颈",
"sidebar_label": "DML 计划调优",
"language": "zh-CN",
"description": "如何对 Doris DML 计划进行调优?本文介绍如何区分导入与查询瓶颈,并提供导入与查询调优的最佳实践入口。",
"keywords": ["Doris DML 调优", "导入性能瓶颈", "查询性能瓶颈", "DML 计划调优", "Doris 导入最佳实践"]
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
"start:zh-CN": "docusaurus start --locale zh-CN",
"start:ja": "docusaurus start --locale ja",
"postinstall": "node scripts/patch-search-tokenize.js",
"prestart": "yarn key-features:generate",
"build": "PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js docusaurus build",
"prebuild": "yarn key-features:generate",
"build:version": "docusaurus set-versions && docusaurus build",
"prebuild:version": "yarn key-features:generate",
"pretypecheck": "yarn key-features:generate",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
Expand Down Expand Up @@ -37,6 +41,7 @@
"docs:lint": "node scripts/docs-governance/report.js --format github",
"docs:lint:changed": "node scripts/docs-governance/report.js --changed --format github",
"docs:report": "node scripts/docs-governance/report.js --format json --output website-quality-governance/generated/docs-governance-report.json",
"key-features:generate": "node scripts/key-features/generate.js",
"docs-governance:test": "node --test scripts/docs-governance/__tests__/*.test.js",
"typecheck": "tsc"
},
Expand Down
142 changes: 142 additions & 0 deletions scripts/key-features/generate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const {
ensureDirForFile,
normalizePath,
parseArgs,
stripMarkdownExtension,
walkMarkdownFiles,
} = require('../docs-governance/lib');

const DOCS_DIR = 'docs-next/key-features';
const DOCS_ROUTE_BASE = '/docs-next/dev';
const OUTPUT_FILE = 'src/generated/key-features.ts';

function slugToRoute(slug, fallbackSlug) {
const raw = typeof slug === 'string' && slug.trim() ? slug.trim() : fallbackSlug;
const normalized = raw.replace(/^\/+/, '/').replace(/\/+$/, '');
return normalized === '/' ? '/' : normalized;
}

function resolveHref(frontMatter, docsRelativePath) {
const cardHref = frontMatter?.featureCard?.href;
if (typeof cardHref === 'string' && cardHref.trim()) {
return cardHref.trim();
}

const fallbackSlug = `/${stripMarkdownExtension(docsRelativePath)}`;
const routeSlug = slugToRoute(frontMatter.slug, fallbackSlug);
return `${DOCS_ROUTE_BASE}${routeSlug}`;
}

function normalizeTags(value, sourcePath) {
if (!Array.isArray(value) || value.length === 0) {
throw new Error(`Missing featureCard.tags in ${sourcePath}`);
}
return value.map((tag) => {
if (typeof tag !== 'string' || !tag.trim()) {
throw new Error(`Invalid featureCard.tags entry in ${sourcePath}`);
}
return tag.trim();
});
}

function parseFeatureDoc(rootDir, absPath, index) {
const raw = fs.readFileSync(absPath, 'utf8');
const parsed = matter(raw);
const data = parsed.data || {};
const featureCard = data.featureCard || {};
const relativePath = normalizePath(path.relative(rootDir, absPath));
const docsRelativePath = normalizePath(path.relative(path.join(rootDir, 'docs-next'), absPath));
const sourcePath = relativePath;
const title = typeof data.title === 'string' ? data.title.trim() : '';
const description = typeof data.description === 'string' ? data.description.trim() : '';

if (!title) {
throw new Error(`Missing required front matter field "title" in ${sourcePath}`);
}
if (!description) {
throw new Error(`Missing required front matter field "description" in ${sourcePath}`);
}

const href = resolveHref(data, docsRelativePath);
const badge =
typeof featureCard.badge === 'string' && featureCard.badge.trim()
? featureCard.badge.trim()
: typeof featureCard.href === 'string' && featureCard.href.trim()
? 'doc'
: undefined;
const id = stripMarkdownExtension(docsRelativePath).replace(/\//g, '-');
return {
id,
title,
description,
tags: normalizeTags(featureCard.tags, sourcePath),
href,
...(badge ? { badge } : {}),
sourcePath,
};
}

function generate({ rootDir = process.cwd(), output = OUTPUT_FILE } = {}) {
const absDocsDir = path.join(rootDir, DOCS_DIR);
if (!fs.existsSync(absDocsDir)) {
throw new Error(`Missing docs directory: ${DOCS_DIR}`);
}

const files = walkMarkdownFiles(rootDir, [DOCS_DIR]);
const cards = files.map((absPath, index) => parseFeatureDoc(rootDir, absPath, index));
cards.sort((a, b) => a.title.localeCompare(b.title) || a.href.localeCompare(b.href));

const seenIds = new Set();
const seenHref = new Set();
for (const card of cards) {
if (seenIds.has(card.id)) {
throw new Error(`Duplicate key-features id: ${card.id}`);
}
if (seenHref.has(card.href)) {
throw new Error(`Duplicate key-features href: ${card.href}`);
}
seenIds.add(card.id);
seenHref.add(card.href);
}

const outputPath = path.resolve(rootDir, output);
ensureDirForFile(outputPath);
const file = `/* AUTO-GENERATED FILE. DO NOT EDIT DIRECTLY. */
export type KeyFeatureCard = {
id: string;
title: string;
description: string;
tags: string[];
href: string;
badge?: string;
};

export const keyFeatureCards: KeyFeatureCard[] = ${JSON.stringify(
cards.map(({ sourcePath, ...card }) => card),
null,
2,
)};
`;
fs.writeFileSync(outputPath, `${file}\n`, 'utf8');
return cards;
}

function runCli() {
const args = parseArgs(process.argv.slice(2));
const rootDir = args.root ? path.resolve(process.cwd(), args.root) : process.cwd();
const output = args.output || OUTPUT_FILE;
generate({ rootDir, output });
}

if (require.main === module) {
runCli();
}

module.exports = {
generate,
};
2 changes: 1 addition & 1 deletion src/components/home-next/NavbarNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ function buildNavItems(docsHref: string, releasesHref: string): NavItem[] {
{
label: 'Why Doris',
items: [
{ label: 'Key Features (coming soon)', href: '#' },
{ label: 'Doris vs. Others', href: '/why-doris/compare' },
{ label: 'Benchmarks (coming soon)', href: '#' },
{ label: 'Key Features', href: '/why-doris/key-features' },
{ label: 'User Stories (coming soon)', href: '#' },
],
},
Expand Down
35 changes: 9 additions & 26 deletions src/components/use-cases-next/AIAnalyticsNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -486,13 +486,6 @@ const capabilities: Capability[] = [
poweredLabel: 'Powered by',
poweredBy: [
'VARIANT data type',
'JSON analytics',
'Dynamic schema support',
'Nested field access',
'Flexible ingestion',
'Semi-structured analytics',
'Auto-columnar storage for hot fields',
'SQL exploration over dynamic data',
],
},
{
Expand All @@ -509,15 +502,12 @@ const capabilities: Capability[] = [
'Apache Doris brings SQL filtering, full-text search, BM25 relevance scoring, and vector search into one analytical engine for RAG, enterprise search, AI copilots, agent memory, and AI observability. Teams can retrieve the right context from documents, logs, prompts, responses, feedback, and embeddings while applying business filters such as tenant, user, time range, permissions, model version, and workflow status.',
poweredLabel: 'Powered by',
poweredBy: [
'Inverted index',
'Tokenized full-text search',
'BM25 relevance scoring',
'Vector index (HNSW)',
'Vector similarity search',
'Structured SQL filters',
'JSON and metadata filters',
'Hybrid search in SQL',
'RAG-ready retrieval',
'Inverted Index',
'Full-text Search',
'BM25',
'Vector Index',
'Embedding',
'Reciprocal Rank Fusion',
],
},
{
Expand All @@ -535,15 +525,8 @@ const capabilities: Capability[] = [
poweredLabel: 'Powered by',
poweredBy: [
'LLM SQL functions',
'Text summarization in SQL',
'Sentiment analysis in SQL',
'Classification and extraction',
'MCP server',
'SQL interface for agents and tools',
'API and connector integration',
'Agent framework integration',
'LLMOps and observability integration',
'Unified analytics for AI signals',
'MCP Server',
'Semantic Layer(Coming Soon)',
],
},
];
Expand Down Expand Up @@ -750,7 +733,7 @@ function CtaSection(): JSX.Element {
with <span className="accent">Apache Doris.</span>
</h2>
<div className="cta-actions" data-reveal data-reveal-delay="2">
<Link className="btn btn-yellow" to="/download">
<Link className="btn btn-yellow" to="/docs-next/dev/getting-started/quick-start">
<svg
width="14"
height="14"
Expand Down
36 changes: 22 additions & 14 deletions src/components/use-cases-next/CustomerFacingAnalyticsNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,13 @@ const capabilities: Capability[] = [
desc: 'New data becomes queryable within seconds, while dashboards and in-product analytics stay fast and interactive. Users see the latest activity as it happens, not after the next batch cycle.',
poweredLabel: 'Powered by',
poweredBy: [
{ label: 'Stream ingestion from Kafka and CDC', href: '#' },
{ label: 'Incremental materialized view refresh', href: '#' },
{ label: 'Real-time query visibility', href: '#' },
{ label: 'Load Transaction', href: '#' },
{ label: 'Data Compaction', href: '#' },
{ label: 'Data Update/Delete', href: '#' },
{ label: 'Preaggregation', href: '#' },
{ label: 'Group Commit', href: '#' },
{ label: 'Kafka/CDC Integration', href: '#' },
{ label: 'Incremental Materialized View', href: '#' },
],
},
{
Expand All @@ -440,10 +444,13 @@ const capabilities: Capability[] = [
desc: 'Apache Doris sustains fast, predictable query response times as concurrent users and data volumes grow, not just in single-query benchmarks.',
poweredLabel: 'Powered by',
poweredBy: [
{ label: 'MPP execution engine', href: '#' },
{ label: 'Vectorized execution', href: '#' },
{ label: 'Advanced query optimizer', href: '#' },
{ label: 'Columnar storage and compression', href: '#' },
{ label: 'Data Pruning', href: '#' },
{ label: 'High Concurrency Point Query', href: '#' },
{ label: 'Vectorized Execution', href: '#' },
{ label: 'Columnar Storage', href: '#' },
{ label: 'Prepared Statement', href: '#' },
{ label: 'Query Cache', href: '#' },
{ label: 'Condition Cache', href: '#' },
],
},
{
Expand All @@ -459,9 +466,10 @@ const capabilities: Capability[] = [
desc: 'Serve many users, teams, or tenants from a single platform. Isolate workloads and control resource usage so heavy queries from one tenant do not impact others.',
poweredLabel: 'Powered by',
poweredBy: [
{ label: 'Resource isolation', href: '#' },
{ label: 'High-concurrency scheduling', href: '#' },
{ label: 'Query queueing', href: '#' },
{ label: 'Workload Group', href: '#' },
{ label: 'Resource Group', href: '#' },
{ label: 'Compute Group', href: '#' },
{ label: 'Pipleline Execution Engine', href: '#' },
],
},
{
Expand All @@ -475,9 +483,9 @@ const capabilities: Capability[] = [
desc: 'Query open lakehouse formats directly. Combine real-time serving with existing data lake architectures, without copying data twice.',
poweredLabel: 'Powered by',
poweredBy: [
{ label: 'Iceberg and lakehouse query capabilities', href: '#' },
{ label: 'Zero-copy analytics', href: '#' },
{ label: 'Unified access to operational and historical data', href: '#' },
{ label: 'Parquet Reader Optzimation', href: '#' },
{ label: 'Data Cache & Page Cache', href: '#' },
{ label: 'Metadata Cache', href: '#' },
],
},
];
Expand Down Expand Up @@ -653,7 +661,7 @@ function CTASection(): JSX.Element {
with <span className="accent">Apache Doris.</span>
</h2>
<div className="cta-actions" data-reveal data-reveal-delay="2">
<Link className="btn btn-yellow" to="/download">
<Link className="btn btn-yellow" to="/docs-next/dev/getting-started/quick-start">
<svg
width="14"
height="14"
Expand Down
Loading
Loading