Skip to content

Commit

Permalink
Addressing review comments
Browse files Browse the repository at this point in the history
Signed-off-by: Bharathwaj G <bharath78910@gmail.com>
  • Loading branch information
bharath-techie committed Jun 26, 2024
1 parent 680875e commit 92b8480
Show file tree
Hide file tree
Showing 12 changed files with 304 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,21 @@

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.index.IndexSettings;
import org.opensearch.index.compositeindex.datacube.Dimension;
import org.opensearch.index.compositeindex.datacube.Metric;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeIndexSettings;
import org.opensearch.index.mapper.CompositeMappedFieldType;
import org.opensearch.index.mapper.MappedFieldType;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeValidator;
import org.opensearch.index.mapper.MapperService;
import org.opensearch.index.mapper.StarTreeMapper;

import java.util.Locale;
import java.util.Set;

/**
* Validation for composite indices
* Validation for composite indices as part of mappings
*
* @opensearch.experimental
*/
@ExperimentalApi
public class CompositeIndexValidator {

public static void validate(MapperService mapperService, CompositeIndexSettings compositeIndexSettings, IndexSettings indexSettings) {
validateStarTreeMappings(mapperService, compositeIndexSettings, indexSettings);
StarTreeValidator.validate(mapperService, compositeIndexSettings, indexSettings);
}

public static void validate(
Expand All @@ -47,74 +41,6 @@ public static void validate(
)
);
}
validateStarTreeMappings(mapperService, compositeIndexSettings, indexSettings);
}

private static void validateStarTreeMappings(
MapperService mapperService,
CompositeIndexSettings compositeIndexSettings,
IndexSettings indexSettings
) {
Set<CompositeMappedFieldType> compositeFieldTypes = mapperService.getCompositeFieldTypes();
if (compositeFieldTypes.size() > StarTreeIndexSettings.STAR_TREE_MAX_FIELDS_SETTING.get(indexSettings.getSettings())) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Index cannot have more than [%s] star tree fields",
StarTreeIndexSettings.STAR_TREE_MAX_FIELDS_SETTING.get(indexSettings.getSettings())
)
);
}
for (CompositeMappedFieldType compositeFieldType : compositeFieldTypes) {
if (!(compositeFieldType instanceof StarTreeMapper.StarTreeFieldType)) {
continue;
}
if (!compositeIndexSettings.isStarTreeIndexCreationEnabled()) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"star tree index cannot be created, enable it using [%s] setting",
CompositeIndexSettings.STAR_TREE_INDEX_ENABLED_SETTING.getKey()
)
);
}
StarTreeMapper.StarTreeFieldType dataCubeFieldType = (StarTreeMapper.StarTreeFieldType) compositeFieldType;
for (Dimension dim : dataCubeFieldType.getDimensions()) {
MappedFieldType ft = mapperService.fieldType(dim.getField());
if (ft == null) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "unknown dimension field [%s] as part of star tree field", dim.getField())
);
}
if (ft.isAggregatable() == false) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Aggregations not supported for the dimension field [%s] with field type [%s] as part of star tree field",
dim.getField(),
ft.typeName()
)
);
}
}
for (Metric metric : dataCubeFieldType.getMetrics()) {
MappedFieldType ft = mapperService.fieldType(metric.getField());
if (ft == null) {
throw new IllegalArgumentException(
String.format(Locale.ROOT, "unknown metric field [%s] as part of star tree field", metric.getField())
);
}
if (ft.isAggregatable() == false) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Aggregations not supported for the metrics field [%s] with field type [%s] as part of star tree field",
metric.getField(),
ft.typeName()
)
);
}
}
}
StarTreeValidator.validate(mapperService, compositeIndexSettings, indexSettings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,28 @@

import org.opensearch.common.Rounding;
import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.common.xcontent.support.XContentMapValues;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeIndexSettings;
import org.opensearch.index.mapper.Mapper;
import org.opensearch.index.mapper.StarTreeMapper;
import org.opensearch.index.mapper.CompositeDataCubeFieldType;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Date dimension class
*
* @opensearch.experimental
*/
@ExperimentalApi
public class DateDimension extends Dimension {
public class DateDimension implements Dimension {
private final List<Rounding.DateTimeUnit> calendarIntervals;
public static final String CALENDAR_INTERVALS = "calendar_intervals";
public static final String DATE = "date";
private final String field;

public DateDimension(String name, Map<String, Object> dimensionMap, Mapper.TypeParser.ParserContext c) {
super(name);
List<String> intervalStrings = XContentMapValues.extractRawValues(CALENDAR_INTERVALS, dimensionMap)
.stream()
.map(Object::toString)
.collect(Collectors.toList());
if (intervalStrings == null || intervalStrings.isEmpty()) {
this.calendarIntervals = StarTreeIndexSettings.DEFAULT_DATE_INTERVALS.get(c.getSettings());
} else {
if (intervalStrings.size() > StarTreeIndexSettings.STAR_TREE_MAX_DATE_INTERVALS_SETTING.get(c.getSettings())) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"At most [%s] calendar intervals are allowed in dimension [%s]",
StarTreeIndexSettings.STAR_TREE_MAX_DATE_INTERVALS_SETTING.get(c.getSettings()),
name
)
);
}
Set<Rounding.DateTimeUnit> calendarIntervals = new LinkedHashSet<>();
for (String interval : intervalStrings) {
calendarIntervals.add(StarTreeIndexSettings.getTimeUnit(interval));
}
this.calendarIntervals = new ArrayList<>(calendarIntervals);
}
dimensionMap.remove(CALENDAR_INTERVALS);
public DateDimension(String field, List<Rounding.DateTimeUnit> calendarIntervals) {
this.field = field;
this.calendarIntervals = calendarIntervals;
}

public List<Rounding.DateTimeUnit> getIntervals() {
Expand All @@ -72,8 +41,8 @@ public List<Rounding.DateTimeUnit> getIntervals() {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(StarTreeMapper.NAME, this.getField());
builder.field(StarTreeMapper.TYPE, DATE);
builder.field(CompositeDataCubeFieldType.NAME, this.getField());
builder.field(CompositeDataCubeFieldType.TYPE, DATE);
builder.startArray(CALENDAR_INTERVALS);
for (Rounding.DateTimeUnit interval : calendarIntervals) {
builder.value(interval.shortName());
Expand All @@ -87,13 +56,17 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
DateDimension that = (DateDimension) o;
return Objects.equals(calendarIntervals, that.calendarIntervals);
return Objects.equals(field, that.getField()) && Objects.equals(calendarIntervals, that.calendarIntervals);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), calendarIntervals);
}

@Override
public String getField() {
return field;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,13 @@

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.index.mapper.StarTreeMapper;

import java.io.IOException;
import java.util.Objects;

/**
* Composite index dimension base class
* Base interface for data-cube dimensions
*
* @opensearch.experimental
*/
@ExperimentalApi
public class Dimension implements ToXContent {
public static final String NUMERIC = "numeric";
private final String field;

public Dimension(String field) {
this.field = field;
}

public String getField() {
return field;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(StarTreeMapper.NAME, field);
builder.field(StarTreeMapper.TYPE, NUMERIC);
builder.endObject();
return builder;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dimension dimension = (Dimension) o;
return Objects.equals(field, dimension.field);
}

@Override
public int hashCode() {
return Objects.hash(field);
}
public interface Dimension extends ToXContent {
String getField();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.index.compositeindex.datacube;

import org.opensearch.common.Rounding;
import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.common.xcontent.support.XContentMapValues;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeIndexSettings;
import org.opensearch.index.mapper.DateFieldMapper;
import org.opensearch.index.mapper.Mapper;
import org.opensearch.index.mapper.NumberFieldMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

import static org.opensearch.index.compositeindex.datacube.DateDimension.CALENDAR_INTERVALS;

/**
* Dimension factory class mainly used to parse and create dimension from the mappings
*
* @opensearch.experimental
*/
@ExperimentalApi
public class DimensionFactory {
public static Dimension parseAndCreateDimension(
String name,
String type,
Map<String, Object> dimensionMap,
Mapper.TypeParser.ParserContext c
) {
switch (type) {
case DateDimension.DATE:
return parseAndCreateDateDimension(name, dimensionMap, c);
case NumericDimension.NUMERIC:
return new NumericDimension(name);
default:
throw new IllegalArgumentException(
String.format(Locale.ROOT, "unsupported field type associated with dimension [%s] as part of star tree field", name)
);
}
}

public static Dimension parseAndCreateDimension(
String name,
Mapper.Builder builder,
Map<String, Object> dimensionMap,
Mapper.TypeParser.ParserContext c
) {
if (builder instanceof DateFieldMapper.Builder) {
return parseAndCreateDateDimension(name, dimensionMap, c);
} else if (builder instanceof NumberFieldMapper.Builder) {
return new NumericDimension(name);
}
throw new IllegalArgumentException(
String.format(Locale.ROOT, "unsupported field type associated with star tree dimension [%s]", name)
);
}

private static DateDimension parseAndCreateDateDimension(
String name,
Map<String, Object> dimensionMap,
Mapper.TypeParser.ParserContext c
) {
List<Rounding.DateTimeUnit> calendarIntervals = new ArrayList<>();
List<String> intervalStrings = XContentMapValues.extractRawValues(CALENDAR_INTERVALS, dimensionMap)
.stream()
.map(Object::toString)
.collect(Collectors.toList());
if (intervalStrings == null || intervalStrings.isEmpty()) {
calendarIntervals = StarTreeIndexSettings.DEFAULT_DATE_INTERVALS.get(c.getSettings());
} else {
if (intervalStrings.size() > StarTreeIndexSettings.STAR_TREE_MAX_DATE_INTERVALS_SETTING.get(c.getSettings())) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"At most [%s] calendar intervals are allowed in dimension [%s]",
StarTreeIndexSettings.STAR_TREE_MAX_DATE_INTERVALS_SETTING.get(c.getSettings()),
name
)
);
}
for (String interval : intervalStrings) {
calendarIntervals.add(StarTreeIndexSettings.getTimeUnit(interval));
}
calendarIntervals = new ArrayList<>(calendarIntervals);
}
dimensionMap.remove(CALENDAR_INTERVALS);
return new DateDimension(name, calendarIntervals);
}
}
Loading

0 comments on commit 92b8480

Please sign in to comment.