Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
8eaf91c
fix(sitesearch): preserve the custom index alias across a crawl (#36983)
fabrizzio-dotCMS Aug 11, 2026
9509241
feat(migration): report the Site Search alias per engine in the readi…
fabrizzio-dotCMS Aug 11, 2026
921a06e
fix(sitesearch): resolve aliases across both engines for management v…
fabrizzio-dotCMS Aug 11, 2026
36eeef0
docs(migration): state the driftPercent formula and the +100.0 case (…
fabrizzio-dotCMS Aug 11, 2026
4db7176
docs(migration): document the _stats lag on the readiness content cou…
fabrizzio-dotCMS Aug 11, 2026
bafc6a4
fix(migration): count content indices with a query, not the _stats co…
fabrizzio-dotCMS Aug 11, 2026
c276077
docs(migration): the Site Search crawl inherits the content index (#3…
fabrizzio-dotCMS Aug 11, 2026
181b82b
feat(migration): report content index coverage against the database (…
fabrizzio-dotCMS Aug 11, 2026
ccc3e39
feat(sitesearch): warn before a crawl reads an incomplete content ind…
fabrizzio-dotCMS Aug 11, 2026
0289874
fix(migration): count the coverage denominator exactly (#36983)
fabrizzio-dotCMS Aug 11, 2026
af8d6f5
docs(migration): correct the coverage query's plan and cost with meas…
fabrizzio-dotCMS Aug 11, 2026
6a335e8
refactor(migration): name the readiness completeness fields for what …
fabrizzio-dotCMS Aug 11, 2026
c57ce47
docs(migration): align the readiness sections with the renamed fields…
fabrizzio-dotCMS Aug 11, 2026
a26fb1c
fix(sitesearch): resolve the default index phase-aware, not from the …
fabrizzio-dotCMS Aug 11, 2026
57b10b8
refactor(migration): declare the readiness count SQL as a literal con…
fabrizzio-dotCMS Aug 11, 2026
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
288 changes: 285 additions & 3 deletions docs/backend/OPENSEARCH_MIGRATION.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import io.vavr.control.Try;
Expand Down Expand Up @@ -370,9 +371,16 @@ public SiteSearchResults search(String indexName, String query, int offset, int
* @return
* @throws DotDataException
*/
@Override
public Optional<String> defaultIndexName() throws DotDataException {
return Optional.ofNullable(indiciesAPI.loadIndicies().getSiteSearch());
}

@Override
public boolean isDefaultIndex(final String indexName) throws DotDataException {
return indexName.equals(indiciesAPI.loadIndicies().getSiteSearch());
// Defined in terms of defaultIndexName so "which index is the default" has one definition
// per engine (issue #36983).
return indexName != null && defaultIndexName().filter(indexName::equals).isPresent();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,16 @@ public Map<String, Aggregation> getFacets(String indexName, String query) throws
// Default index activation / inspection
// =========================================================================

@Override
public Optional<String> defaultIndexName() {
return defaultSiteSearchIndex();
}

@Override
public boolean isDefaultIndex(final String indexName) throws DotDataException {
return indexName != null && indexName.equals(defaultSiteSearchIndex().orElse(null));
// Defined in terms of defaultIndexName so "which index is the default" has one definition
// per engine (issue #36983).
return indexName != null && defaultIndexName().filter(indexName::equals).isPresent();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.quartz.SchedulerException;

Expand Down Expand Up @@ -201,6 +203,33 @@ public Map<String, String> getAliasToIndexMap() {
return router.read(SiteSearchAPI::getAliasToIndexMap);
}

/**
* Router: alias resolution over the SAME provider set {@link #listIndices()} uses, so every listed
* index can show its alias — the management/display view (issue #36983).
*
* <p>Deliberately NOT the read provider alone. The list is a union in the dual-write phases, so an
* index living only on the other engine would otherwise render with a blank alias: Phase 2 + a
* Phase-0 (ES-only) index, or Phase 1 + a Phase-3 (OS-only) index after a downgrade. Merging over
* the write providers keeps the alias view and the index list exactly in step.</p>
*
* <p>The read provider is applied last so it wins any collision: if the two engines resolve one
* alias to different logical indices (a mirror desync), the map agrees with what a search would
* actually hit. In the single-provider phases (0 and 3) there is nothing to merge.</p>
*/
@Override
public Map<String, String> getAliasToIndexMapAllEngines() {
final List<SiteSearchAPI> providers = router.writeProviders();
if (providers.size() == 1) {
return providers.getFirst().getAliasToIndexMap();
}
final SiteSearchAPI readProvider = router.readProvider();
final Map<String, String> merged = new LinkedHashMap<>();
providers.stream().filter(provider -> provider != readProvider)
.forEach(provider -> merged.putAll(provider.getAliasToIndexMap()));
merged.putAll(readProvider.getAliasToIndexMap()); // last write wins → read provider
return merged;
}

// -------------------------------------------------------------------------
// Reads — read provider
// -------------------------------------------------------------------------
Expand All @@ -221,6 +250,23 @@ public SiteSearchResult getFromIndex(final String index, final String id) {
return router.read(impl -> impl.getFromIndex(index, id));
}

/**
* Router: the default site-search index according to the current read provider — Elasticsearch's
* legacy pointer in Phases 0/1, OpenSearch's {@code VersionedIndices} (with a legacy fallback) in
* Phases 2/3. Reading the legacy pointer directly goes stale from Phase 3 on, where
* {@code activateIndex} fans out to OpenSearch alone (issue #36983).
*/
@Override
public Optional<String> defaultIndexName() throws DotDataException {
try {
return router.readChecked(SiteSearchAPI::defaultIndexName);
} catch (DotDataException e) {
throw e;
} catch (Exception e) {
throw new DotDataException(e.getMessage(), e);
}
}

@Override
public boolean isDefaultIndex(final String indexName) throws DotDataException {
try {
Expand Down
Loading
Loading