Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
351ce66
fix(sitesearch): vendor-neutral aggregation abstraction (#35786)
fabrizzio-dotCMS Jun 23, 2026
b064685
feat(sitesearch): OpenSearch impl + phase-aware router for Site Searc…
fabrizzio-dotCMS Jun 23, 2026
fa688d9
Merge branch 'main' into issue-35786-sitesearch-neutral-aggregation
fabrizzio-dotCMS Jun 23, 2026
3ebdc53
fix(sitesearch): use OpenSearch-format index settings for OS site search
fabrizzio-dotCMS Jun 23, 2026
c0fb1ac
fix(sitesearch): apply OS site-search mapping to the untagged physica…
fabrizzio-dotCMS Jun 23, 2026
aadbb3b
test(sitesearch): integration test for SiteSearchWebAPI view tool (#3…
fabrizzio-dotCMS Jun 23, 2026
5c0a4df
fix(sitesearch): isolate dual-write fan-out per provider and pin ES m…
fabrizzio-dotCMS Jun 23, 2026
a3de853
Merge branch 'main' into issue-35786-sitesearch-neutral-aggregation
wezell Jun 24, 2026
ef98534
fix(sitesearch): add dedicated os-sitesearch-mapping.json for the OS …
fabrizzio-dotCMS Jun 24, 2026
80b3341
Merge branch 'main' into issue-35786-sitesearch-neutral-aggregation
fabrizzio-dotCMS Jun 24, 2026
ba8e964
fix(sitesearch): harden OS write error handling + close getMetadata g…
fabrizzio-dotCMS Jun 24, 2026
1fbc89b
Merge branch 'main' into issue-35786-sitesearch-neutral-aggregation
fabrizzio-dotCMS Jun 24, 2026
86bf0fb
fix(sitesearch): preserve top_hits _source on the OpenSearch aggregat…
fabrizzio-dotCMS Jun 24, 2026
de9955b
Merge branch 'main' into issue-35786-sitesearch-neutral-aggregation
fabrizzio-dotCMS Jun 25, 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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import com.dotcms.content.elasticsearch.business.*;
import com.dotcms.content.elasticsearch.util.RestHighLevelClientProvider;
import com.dotcms.content.index.IndexAPI;
import com.dotcms.content.index.IndexTag;
import com.dotcms.content.index.domain.Aggregation;
import com.dotcms.content.index.domain.DotSearchException;
import com.dotcms.enterprise.LicenseUtil;
import com.dotcms.enterprise.license.LicenseLevel;
import com.dotcms.enterprise.priv.util.SearchSourceBuilderUtil;
Expand Down Expand Up @@ -64,7 +67,6 @@
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
Expand All @@ -88,7 +90,11 @@ public ESSiteSearchAPI(final IndexAPI indexApi,
}

public ESSiteSearchAPI() {
this(APILocator.getESIndexAPI(), new ESMappingAPIImpl(), APILocator.getIndiciesAPI());
// Use the vendor-specific ESIndexAPI directly (NOT APILocator.getESIndexAPI(), which returns
// the phase-aware IndexAPIImpl router). The SiteSearchAPIImpl router is the single fan-out
// point for the ES → OS migration; routing index ops through the neutral router here as well
// would dual-write a second time and create duplicate OpenSearch indices.
this(new ESIndexAPI(), new ESMappingAPIImpl(), APILocator.getIndiciesAPI());
}

/**
Expand Down Expand Up @@ -351,7 +357,7 @@ public void deactivateIndex(String indexName) throws DotDataException, IOExcepti
}

@Override
public synchronized boolean createSiteSearchIndex(String indexName, String alias, int shards) throws ElasticsearchException, IOException {
public synchronized boolean createSiteSearchIndex(String indexName, String alias, int shards) throws DotSearchException, IOException {
if(indexName==null){
return false;
}
Expand Down Expand Up @@ -379,16 +385,20 @@ public synchronized boolean createSiteSearchIndex(String indexName, String alias
}

if(i++ > 300){
throw new ElasticsearchException("index timed out creating");
throw new DotSearchException("index timed out creating");
}
}

if(UtilMethods.isSet(alias)){
indexApi.createAlias(indexName, alias);
}

//put mappings
mappingAPI.putMapping(indexName, mapping);
// Put mappings on the ES index only. ESMappingAPIImpl.putMapping(String, String) is
// phase-dispatched and would fan out to OpenSearch, but SiteSearchAPIImpl is already the
// single fan-out point for site search (it invokes OSSiteSearchAPI separately, which owns
// its own untagged OS index + mapping). Fanning out here too would re-issue the mapping to
// a `.os`-tagged physical name that site-search OS indices never use → HTTP 404. Pin to ES.
mappingAPI.putMapping(List.of(indexName), mapping, IndexTag.ES);

return true;
}
Expand Down Expand Up @@ -634,7 +644,7 @@ public Map<String, Aggregation> getAggregations ( String indexName, String query
}

if ( indexName == null || !IndexType.SITE_SEARCH.is(indexName) ) {
throw new ElasticsearchException( indexName + " is not a sitesearch index or alias" );
throw new DotSearchException( indexName + " is not a sitesearch index or alias" );
}

//https://github.com/elasticsearch/elasticsearch/issues/2980
Expand All @@ -648,10 +658,10 @@ public Map<String, Aggregation> getAggregations ( String indexName, String query
.timeout(TimeValue.timeValueMillis(INDEX_OPERATIONS_TIMEOUT_IN_MS)));

final SearchResponse response = client.search(request, RequestOptions.DEFAULT);
return response.getAggregations().asMap();
return Aggregation.from(response.getAggregations());
} catch ( ElasticsearchException | IOException e ) {
Logger.error( this.getClass(), "Error getting aggregations for query.\n" + e.getMessage(), e );
throw new ElasticsearchException( "Error getting aggregations for query.\n" + e.getMessage(), e );
throw new DotSearchException( "Error getting aggregations for query.\n" + e.getMessage(), e );
}
}

Expand All @@ -669,7 +679,7 @@ public Map<String, Aggregation> getFacets ( String indexName, String query ) thr
}

if ( indexName == null || !IndexType.SITE_SEARCH.is(indexName ) ) {
throw new ElasticsearchException( indexName + " is not a sitesearch index or alias" );
throw new DotSearchException( indexName + " is not a sitesearch index or alias" );
}

//https://github.com/elasticsearch/elasticsearch/issues/2980
Expand All @@ -683,10 +693,10 @@ public Map<String, Aggregation> getFacets ( String indexName, String query ) thr
.timeout(TimeValue.timeValueMillis(INDEX_OPERATIONS_TIMEOUT_IN_MS)));

final SearchResponse response = client.search(request, RequestOptions.DEFAULT);
return response.getAggregations().asMap();
return Aggregation.from(response.getAggregations());
} catch ( ElasticsearchException | IOException e ) {
Logger.error( this.getClass(), "Error getting Facets for query.\n" + e.getMessage(), e );
throw new ElasticsearchException( "Error getting Facets for query.\n" + e.getMessage(), e );
throw new DotSearchException( "Error getting Facets for query.\n" + e.getMessage(), e );
}
}

Expand Down
Loading
Loading