Skip to content

Commit a417fe7

Browse files
DOC-6026 decision tree improvements
1 parent 1fe1fb2 commit a417fe7

File tree

4 files changed

+291
-44
lines changed

4 files changed

+291
-44
lines changed

build/render_hook_docs/DECISION_TREE_FORMAT.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ scope: documents
137137
7. **Use meaningful scopes**: Choose scope values that clearly indicate the tree's domain (e.g., `documents`, `collections`, `sequences`)
138138
8. **Add sentiment for suitability trees**: If your tree determines whether something is suitable (not just choosing between options), use `sentiment: "positive"` and `sentiment: "negative"` to provide visual feedback
139139
9. **Be consistent with sentiment**: In a suitability tree, ensure all positive outcomes have `sentiment: "positive"` and all negative outcomes have `sentiment: "negative"` for clarity
140+
10. **Control answer order**: The order of `yes` and `no` in the YAML controls the visual layout. For early rejection patterns, put `no` first so negative outcomes appear on the left side of the diagram
140141
141142
## Example: Redis Data Type Selection
142143

build/render_hook_docs/DECISION_TREE_IMPLEMENTATION_NOTES.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,33 @@ outcome:
167167

168168
**Backward Compatibility**: Existing trees without sentiment fields continue to work with default red styling. This allows gradual adoption.
169169

170+
## 12. Answer Order Respects YAML Structure
171+
172+
**Discovery**: The JavaScript had two issues preventing YAML answer order from being respected:
173+
1. The `flattenDecisionTree()` function was hardcoded to process "yes" first, then "no"
174+
2. The tree line drawing code was deriving Yes/No labels from position (first child = Yes, others = No) instead of using the actual answer value
175+
176+
**Problem**: This prevented authors from controlling the visual layout of the tree. If you wanted "no" outcomes to appear first (for early rejection patterns), the diagram would still show "yes" first.
177+
178+
**Solution**:
179+
1. Modified `flattenDecisionTree()` to iterate through answer keys in the order they appear in the YAML
180+
2. Modified `drawTreeLines()` to use the actual `answer` value stored in each item instead of deriving it from position
181+
182+
```javascript
183+
// In flattenDecisionTree():
184+
const answerKeys = Object.keys(question.answers);
185+
answerKeys.forEach(answerKey => {
186+
const answer = question.answers[answerKey];
187+
// Process in order, storing answer.value in the item
188+
});
189+
190+
// In drawTreeLines():
191+
answerLabel = item.answer || 'Yes'; // Use stored value, not position
192+
```
193+
194+
**Benefit**: Authors can now control tree layout by ordering answers in the YAML:
195+
- Put `no` first for early rejection patterns (negative outcomes appear left)
196+
- Put `yes` first for positive-path-first patterns (positive outcomes appear left)
197+
198+
**Key Insight**: YAML object key order is preserved in JavaScript (since ES2015), and we now respect both the order AND the actual answer values, making the layout fully author-controlled.
199+

content/integrate/redis-data-integration/when-to-use.md

Lines changed: 237 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,246 @@ summary: Redis Data Integration keeps Redis in sync with the primary database in
1515
type: integration
1616
weight: 5
1717
---
18-
```decision-tree
19-
```
2018

2119
RDI is designed to support apps that must use a disk-based database as the system of record
2220
but must also be fast and scalable. This is a common requirement for mobile and web
2321
apps with a rapidly-growing number of users; the performance of the main database is fine at first
2422
but it will soon struggle to handle the increasing demand without a cache.
2523

26-
{{< embed-md "rdi-when-to-use.md" >}}
24+
## When to use RDI
25+
26+
RDI is a good fit when:
27+
28+
- You want to use Redis as the target database for caching data.
29+
- You want to transfer data to Redis from a *single* source database.
30+
- You must use a slow database as the system of record for the app.
31+
- The app must always *write* its data to the slow database.
32+
- Your app can tolerate *eventual* consistency of data in the Redis cache.
33+
- You want a self-managed solution or AWS based solution.
34+
- The source data changes frequently in small increments.
35+
- There are no more than 10K changes per second in the source database.
36+
- The total data size is not larger than 100GB.
37+
- RDI throughput during
38+
[full sync]({{< relref "/integrate/redis-data-integration/data-pipelines#pipeline-lifecycle" >}}) would not exceed 30K records per second and during
39+
[CDC]({{< relref "/integrate/redis-data-integration/data-pipelines#pipeline-lifecycle" >}})
40+
would not exceed 10K records per second.
41+
- You don’t need to perform join operations on the data from several tables
42+
into a nested Redis JSON object.
43+
- RDI supports the data transformations you need for your app.
44+
- Your data caching needs are too complex or demanding to implement and maintain yourself.
45+
- Your database administrator has reviewed RDI's requirements for the source database and
46+
confirmed that they are acceptable.
47+
48+
## When not to use RDI
49+
50+
RDI is not a good fit when:
51+
52+
- You are migrating an existing data set into Redis only once.
53+
- Your app needs *immediate* cache consistency (or a hard limit on latency) rather
54+
than *eventual* consistency.
55+
- You need *transactional* consistency between the source and target databases.
56+
- The data is ingested from two replicas of Active-Active at the same time.
57+
- The app must *write* data to the Redis cache, which then updates the source database.
58+
- Your data set will only ever be small.
59+
- Your data is updated by some batch or ETL process with long and large transactions - RDI will fail
60+
processing these changes.
61+
- You need complex stream processing of data (aggregations, sliding window processing, complex
62+
custom logic).
63+
- You need to write data to multiple targets from the same pipeline (Redis supports other
64+
ways to replicate data across Redis databases such as replicaOf and Active Active).
65+
- Your database administrator has rejected RDI's requirements for the source database.
66+
67+
## Decision tree for using RDI
68+
69+
Use the decision tree below to determine whether RDI is a good fit for your architecture:
70+
71+
```decision-tree {id="when-to-use-rdi"}
72+
id: when-to-use-rdi
73+
scope: rdi
74+
rootQuestion: cacheTarget
75+
questions:
76+
cacheTarget:
77+
text: |
78+
Do you want to use Redis as the target database for caching data?
79+
whyAsk: |
80+
RDI is specifically designed to keep Redis in sync with a primary database. If you don't need Redis as a cache, RDI is not the right tool.
81+
answers:
82+
no:
83+
value: "No"
84+
outcome:
85+
label: "RDI is not necessary - you don't need Redis as a cache"
86+
id: noRedisCache
87+
sentiment: "negative"
88+
yes:
89+
value: "Yes"
90+
nextQuestion: singleSource
91+
singleSource:
92+
text: |
93+
Are you transferring data from a single source database?
94+
whyAsk: |
95+
RDI is designed to work with a single source database. Multiple sources or Active-Active replicas create conflicting change events.
96+
answers:
97+
no:
98+
value: "No"
99+
outcome:
100+
label: "RDI won't work - you need a single source database"
101+
id: multipleSourcesOrActiveActive
102+
sentiment: "negative"
103+
yes:
104+
value: "Yes"
105+
nextQuestion: systemOfRecord
106+
systemOfRecord:
107+
text: |
108+
Is the source database your system of record?
109+
whyAsk: |
110+
RDI requires the source database to be the authoritative source of truth. If your app writes to Redis first, RDI won't work.
111+
answers:
112+
no:
113+
value: "No"
114+
outcome:
115+
label: "RDI won't work - the source database must be the system of record"
116+
id: notSystemOfRecord
117+
sentiment: "negative"
118+
yes:
119+
value: "Yes"
120+
nextQuestion: appWritesToDb
121+
appWritesToDb:
122+
text: |
123+
Does your app always write its data to the source database?
124+
whyAsk: |
125+
RDI requires the app to write to the source database first. If your app writes to Redis first, RDI cannot maintain consistency.
126+
answers:
127+
no:
128+
value: "No"
129+
outcome:
130+
label: "RDI won't work - your app must write to the source database"
131+
id: appWritesToRedis
132+
sentiment: "negative"
133+
yes:
134+
value: "Yes"
135+
nextQuestion: consistency
136+
consistency:
137+
text: |
138+
Can your app tolerate eventual consistency in the Redis cache?
139+
whyAsk: |
140+
RDI provides eventual consistency, not immediate consistency. If your app needs real-time cache consistency or hard latency limits, RDI is not suitable.
141+
answers:
142+
no:
143+
value: "No"
144+
outcome:
145+
label: "RDI is not suitable - you need immediate cache consistency"
146+
id: needsImmediate
147+
sentiment: "negative"
148+
yes:
149+
value: "Yes"
150+
nextQuestion: deployment
151+
deployment:
152+
text: |
153+
Do you want a self-managed solution or an AWS-based solution?
154+
whyAsk: |
155+
RDI is available as a self-managed solution or as an AWS-based managed service. If you need a different deployment model, RDI may not be suitable.
156+
answers:
157+
no:
158+
value: "No"
159+
outcome:
160+
label: "RDI may not be suitable - check deployment options"
161+
id: deploymentMismatch
162+
sentiment: "negative"
163+
yes:
164+
value: "Yes"
165+
nextQuestion: dataChangePattern
166+
dataChangePattern:
167+
text: |
168+
Does your source data change frequently in small increments?
169+
whyAsk: |
170+
RDI captures changes from the database transaction log. Large batch transactions or ETL processes can cause RDI to fail.
171+
answers:
172+
no:
173+
value: "No"
174+
outcome:
175+
label: "RDI will fail with batch/ETL processes and large transactions"
176+
id: batchProcessing
177+
sentiment: "negative"
178+
yes:
179+
value: "Yes"
180+
nextQuestion: changeRate
181+
changeRate:
182+
text: |
183+
Are there no more than 10K changes per second in the source database?
184+
whyAsk: |
185+
RDI has throughput limits. Exceeding these limits will cause processing failures and data loss.
186+
answers:
187+
no:
188+
value: "No"
189+
outcome:
190+
label: "RDI throughput limits will be exceeded"
191+
id: exceedsChangeRate
192+
sentiment: "negative"
193+
yes:
194+
value: "Yes"
195+
nextQuestion: dataSize
196+
dataSize:
197+
text: |
198+
Is your total data size not larger than 100GB?
199+
whyAsk: |
200+
RDI has practical limits on the total data size it can manage. Very large datasets may exceed these limits.
201+
answers:
202+
no:
203+
value: "No"
204+
outcome:
205+
label: "RDI may not be suitable - your data set is too large"
206+
id: dataTooLarge
207+
sentiment: "negative"
208+
yes:
209+
value: "Yes"
210+
nextQuestion: joins
211+
joins:
212+
text: |
213+
Do you not need to perform join operations on data from several tables into a nested Redis JSON object?
214+
whyAsk: |
215+
RDI has limitations with complex join operations. If you need to combine data from multiple tables into nested structures, you may need custom transformations.
216+
answers:
217+
no:
218+
value: "No"
219+
outcome:
220+
label: "RDI may not be suitable - complex joins are not well supported"
221+
id: complexJoins
222+
sentiment: "negative"
223+
yes:
224+
value: "Yes"
225+
nextQuestion: transformations
226+
transformations:
227+
text: |
228+
Does RDI support the data transformations you need for your app?
229+
whyAsk: |
230+
RDI provides built-in transformations, but if you need custom logic beyond what RDI supports, you may need a different approach.
231+
answers:
232+
no:
233+
value: "No"
234+
outcome:
235+
label: "RDI may not be suitable - required transformations are not supported"
236+
id: unsupportedTransformations
237+
sentiment: "negative"
238+
yes:
239+
value: "Yes"
240+
nextQuestion: adminReview
241+
adminReview:
242+
text: |
243+
Has your database administrator reviewed and confirmed that RDI's requirements for the source database are acceptable?
244+
whyAsk: |
245+
RDI has specific requirements for the source database (binary logging, permissions, etc.). Your DBA must confirm these are acceptable before proceeding.
246+
answers:
247+
no:
248+
value: "No"
249+
outcome:
250+
label: "RDI is not suitable - database administrator has rejected RDI's requirements"
251+
id: adminRejected
252+
sentiment: "negative"
253+
yes:
254+
value: "Yes"
255+
outcome:
256+
label: "✅ RDI is a good fit for your use case"
257+
id: goodFit
258+
sentiment: "positive"
259+
```
260+

static/js/decision-tree.js

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -85,37 +85,27 @@
8585
});
8686

8787
if (question.answers) {
88-
// Process yes answer
89-
if (question.answers.yes) {
90-
if (question.answers.yes.nextQuestion) {
91-
traverse(question.answers.yes.nextQuestion, depth + 1);
92-
} else if (question.answers.yes.outcome) {
93-
items.push({
94-
id: question.answers.yes.outcome.id,
95-
depth: depth + 1,
96-
type: 'outcome',
97-
text: question.answers.yes.outcome.label || '',
98-
answer: 'Yes',
99-
sentiment: question.answers.yes.outcome.sentiment || null
100-
});
101-
}
102-
}
103-
104-
// Process no answer
105-
if (question.answers.no) {
106-
if (question.answers.no.nextQuestion) {
107-
traverse(question.answers.no.nextQuestion, depth + 1);
108-
} else if (question.answers.no.outcome) {
109-
items.push({
110-
id: question.answers.no.outcome.id,
111-
depth: depth + 1,
112-
type: 'outcome',
113-
text: question.answers.no.outcome.label || '',
114-
answer: 'No',
115-
sentiment: question.answers.no.outcome.sentiment || null
116-
});
88+
// Process answers in the order they appear in the YAML
89+
// This respects the author's intended layout (e.g., "no" first for early rejection)
90+
const answerKeys = Object.keys(question.answers);
91+
92+
answerKeys.forEach(answerKey => {
93+
const answer = question.answers[answerKey];
94+
if (answer) {
95+
if (answer.nextQuestion) {
96+
traverse(answer.nextQuestion, depth + 1);
97+
} else if (answer.outcome) {
98+
items.push({
99+
id: answer.outcome.id,
100+
depth: depth + 1,
101+
type: 'outcome',
102+
text: answer.outcome.label || '',
103+
answer: answer.value || answerKey.charAt(0).toUpperCase() + answerKey.slice(1),
104+
sentiment: answer.outcome.sentiment || null
105+
});
106+
}
117107
}
118-
}
108+
});
119109
}
120110
}
121111

@@ -282,17 +272,9 @@
282272
parentY = calcY + items[i].boxHeight / 2;
283273
parentBoxHeight = items[i].boxHeight;
284274

285-
// Determine if this is a Yes or No answer by checking the parent's answers
286-
// Count how many siblings come before this item
287-
let siblingCount = 0;
288-
for (let k = i + 1; k < itemIndex; k++) {
289-
if (items[k].depth === item.depth) {
290-
siblingCount++;
291-
}
292-
}
293-
294-
// If this is the first child of the parent, it's the "yes" path, otherwise "no"
295-
answerLabel = siblingCount === 0 ? 'Yes' : 'No';
275+
// Use the actual answer value stored in the item
276+
// This respects the order defined in the YAML
277+
answerLabel = item.answer || 'Yes';
296278
break;
297279
}
298280
}

0 commit comments

Comments
 (0)