use of com.baidu.hugegraph.schema.IndexLabel in project incubator-hugegraph by apache.
the class GraphIndexTransaction method updateIndex.
/**
* Update index(user properties) of vertex or edge
* @param ilId the id of index label
* @param element the properties owner
* @param removed remove or add index
*/
protected void updateIndex(Id ilId, HugeElement element, boolean removed) {
SchemaTransaction schema = this.params().schemaTransaction();
IndexLabel indexLabel = schema.getIndexLabel(ilId);
E.checkArgument(indexLabel != null, "Not exist index label with id '%s'", ilId);
// Collect property values of index fields
List<Object> allPropValues = new ArrayList<>();
int fieldsNum = indexLabel.indexFields().size();
int firstNullField = fieldsNum;
for (Id fieldId : indexLabel.indexFields()) {
HugeProperty<Object> property = element.getProperty(fieldId);
if (property == null) {
E.checkState(hasNullableProp(element, fieldId), "Non-null property '%s' is null for '%s'", this.graph().propertyKey(fieldId), element);
if (firstNullField == fieldsNum) {
firstNullField = allPropValues.size();
}
allPropValues.add(ConditionQuery.INDEX_VALUE_NULL);
} else {
allPropValues.add(property.value());
}
}
if (firstNullField == 0 && !indexLabel.indexType().isUnique()) {
// The property value of first index field is null
return;
}
// Not build index for record with nullable field (except unique index)
List<Object> nnPropValues = allPropValues.subList(0, firstNullField);
// Expired time
long expiredTime = element.expiredTime();
// Update index for each index type
switch(indexLabel.indexType()) {
case RANGE_INT:
case RANGE_FLOAT:
case RANGE_LONG:
case RANGE_DOUBLE:
E.checkState(nnPropValues.size() == 1, "Expect only one property in range index");
Object value = NumericUtil.convertToNumber(nnPropValues.get(0));
this.updateIndex(indexLabel, value, element.id(), expiredTime, removed);
break;
case SEARCH:
E.checkState(nnPropValues.size() == 1, "Expect only one property in search index");
value = nnPropValues.get(0);
Set<String> words = this.segmentWords(propertyValueToString(value));
for (String word : words) {
this.updateIndex(indexLabel, word, element.id(), expiredTime, removed);
}
break;
case SECONDARY:
// Secondary index maybe include multi prefix index
if (isCollectionIndex(nnPropValues)) {
/*
* Property value is a collection
* we should create index for each item
*/
for (Object propValue : (Collection<?>) nnPropValues.get(0)) {
value = ConditionQuery.concatValues(propValue);
this.updateIndex(indexLabel, value, element.id(), expiredTime, removed);
}
} else {
for (int i = 0, n = nnPropValues.size(); i < n; i++) {
List<Object> prefixValues = nnPropValues.subList(0, i + 1);
value = ConditionQuery.concatValues(prefixValues);
this.updateIndex(indexLabel, value, element.id(), expiredTime, removed);
}
}
break;
case SHARD:
value = ConditionQuery.concatValues(nnPropValues);
this.updateIndex(indexLabel, value, element.id(), expiredTime, removed);
break;
case UNIQUE:
value = ConditionQuery.concatValues(allPropValues);
assert !"".equals(value);
Id id = element.id();
// TODO: add lock for updating unique index
if (!removed && this.existUniqueValue(indexLabel, value, id)) {
throw new IllegalArgumentException(String.format("Unique constraint %s conflict is found for %s", indexLabel, element));
}
this.updateIndex(indexLabel, value, element.id(), expiredTime, removed);
break;
default:
throw new AssertionError(String.format("Unknown index type '%s'", indexLabel.indexType()));
}
}
use of com.baidu.hugegraph.schema.IndexLabel in project incubator-hugegraph by apache.
the class GraphIndexTransaction method collectMatchedIndex.
/**
* Collect matched IndexLabel(s) in a SchemaLabel for a query
* @param schemaLabel find indexLabels of this schemaLabel
* @param query conditions container
* @return MatchedLabel object contains schemaLabel and matched indexLabels
*/
@Watched(prefix = "index")
private MatchedIndex collectMatchedIndex(SchemaLabel schemaLabel, ConditionQuery query) {
SchemaTransaction schema = this.params().schemaTransaction();
Set<IndexLabel> ils = InsertionOrderUtil.newSet();
for (Id il : schemaLabel.indexLabels()) {
IndexLabel indexLabel = schema.getIndexLabel(il);
/*
* Method schema#getIndexLabel may return null here
* because the indexLabel is being created at this time
* and has not been saved to the backend storage
*/
if (indexLabel == null || indexLabel.indexType().isUnique()) {
continue;
}
ils.add(indexLabel);
}
if (this.graph().readMode().showOlap()) {
for (IndexLabel il : schema.getIndexLabels()) {
if (il.olap()) {
ils.add(il);
}
}
}
if (ils.isEmpty()) {
return null;
}
// Try to match single or composite index
Set<IndexLabel> matchedILs = matchSingleOrCompositeIndex(query, ils);
if (matchedILs.isEmpty()) {
// Try to match joint indexes
matchedILs = matchJointIndexes(query, ils);
}
if (!matchedILs.isEmpty()) {
return new MatchedIndex(schemaLabel, matchedILs);
}
return null;
}
use of com.baidu.hugegraph.schema.IndexLabel in project incubator-hugegraph by apache.
the class GraphIndexTransaction method buildJointIndexesQueries.
private static IndexQueries buildJointIndexesQueries(ConditionQuery query, MatchedIndex index) {
IndexQueries queries = IndexQueries.of(query);
List<IndexLabel> allILs = new ArrayList<>(index.indexLabels());
// Handle range/search indexes
if (query.hasRangeCondition() || query.hasSearchCondition()) {
Set<IndexLabel> matchedILs = matchRangeOrSearchIndexLabels(query, index.indexLabels());
assert !matchedILs.isEmpty();
allILs.removeAll(matchedILs);
Set<Id> queryPropKeys = InsertionOrderUtil.newSet();
for (IndexLabel il : matchedILs) {
// Only one field each range/search index-label
queryPropKeys.add(il.indexField());
}
// Construct queries by matched index-labels
queries.putAll(constructQueries(query, matchedILs, queryPropKeys));
// Remove matched queryPropKeys
query = query.copy();
for (Id field : queryPropKeys) {
query.unsetCondition(field);
}
// Return if matched indexes satisfies query-conditions already
if (query.userpropKeys().isEmpty()) {
return queries;
}
}
// Handle secondary joint indexes
final ConditionQuery finalQuery = query;
for (int i = 1, size = allILs.size(); i <= size; i++) {
boolean found = cmn(allILs, size, i, 0, null, r -> {
// All n indexLabels are selected, test current combination
IndexQueries qs = constructJointSecondaryQueries(finalQuery, r);
if (qs.isEmpty()) {
return false;
}
queries.putAll(qs);
return true;
});
if (found) {
return queries;
}
}
return IndexQueries.EMPTY;
}
use of com.baidu.hugegraph.schema.IndexLabel in project incubator-hugegraph by apache.
the class GraphIndexTransaction method queryByLabel.
@Watched(prefix = "index")
private IdHolderList queryByLabel(ConditionQuery query) {
HugeType queryType = query.resultType();
IndexLabel il = IndexLabel.label(queryType);
validateIndexLabel(il);
Id label = query.condition(HugeKeys.LABEL);
assert label != null;
HugeType indexType;
SchemaLabel schemaLabel;
if (queryType.isVertex()) {
indexType = HugeType.VERTEX_LABEL_INDEX;
schemaLabel = this.graph().vertexLabel(label);
} else if (queryType.isEdge()) {
indexType = HugeType.EDGE_LABEL_INDEX;
schemaLabel = this.graph().edgeLabel(label);
} else {
throw new HugeException("Can't query %s by label", queryType);
}
if (!this.store().features().supportsQueryByLabel() && !schemaLabel.enableLabelIndex()) {
throw new NoIndexException("Don't accept query by label '%s', " + "label index is disabled", schemaLabel);
}
ConditionQuery indexQuery = new ConditionQuery(indexType, query);
indexQuery.eq(HugeKeys.INDEX_LABEL_ID, il.id());
indexQuery.eq(HugeKeys.FIELD_VALUES, label);
/*
* We can avoid redundant element ids if set limit, but if there are
* label index overridden by other vertices with different label,
* query with limit like g.V().hasLabel('xx').limit(10) may lose some
* results, so can't set limit here. But in this case, the following
* query results may be still different:
* g.V().hasLabel('xx').count() // label index count
* g.V().hasLabel('xx').limit(-1).count() // actual vertices count
* It’s a similar situation for the offset, like:
* g.V().hasLabel('xx').range(26, 27)
* g.V().hasLabel('xx').range(27, 28)
* we just reset limit here, but don't reset offset due to performance
* optimization with index+offset query, see Query.skipOffsetIfNeeded().
* NOTE: if set offset the backend itself will skip the offset
*/
indexQuery.copyBasic(query);
indexQuery.limit(Query.NO_LIMIT);
IdHolder idHolder = this.doIndexQuery(il, indexQuery);
IdHolderList holders = new IdHolderList(query.paging());
holders.add(idHolder);
return holders;
}
use of com.baidu.hugegraph.schema.IndexLabel in project incubator-hugegraph by apache.
the class GraphIndexTransaction method relatedIndexLabels.
private static Set<IndexLabel> relatedIndexLabels(HugeElement element) {
Set<IndexLabel> indexLabels = InsertionOrderUtil.newSet();
Set<Id> indexLabelIds = element.schemaLabel().indexLabels();
for (Id id : indexLabelIds) {
IndexLabel indexLabel = element.graph().indexLabel(id);
indexLabels.add(indexLabel);
}
return indexLabels;
}
Aggregations