Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix left range index #1498

Merged
merged 4 commits into from
Aug 11, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 @@ -19,6 +19,7 @@

package com.baidu.hugegraph.backend.query;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
Expand All @@ -37,6 +38,7 @@
import com.baidu.hugegraph.backend.query.Condition.RelationType;
import com.baidu.hugegraph.perf.PerfUtil.Watched;
import com.baidu.hugegraph.structure.HugeElement;
import com.baidu.hugegraph.structure.HugeProperty;
import com.baidu.hugegraph.type.HugeType;
import com.baidu.hugegraph.type.define.CollectionType;
import com.baidu.hugegraph.type.define.HugeKeys;
Expand All @@ -46,6 +48,7 @@
import com.baidu.hugegraph.util.collection.CollectionFactory;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

public final class ConditionQuery extends IdQuery {

Expand All @@ -56,6 +59,7 @@ public final class ConditionQuery extends IdQuery {

private OptimizedType optimizedType = OptimizedType.NONE;
private Function<HugeElement, Boolean> resultsFilter = null;
private Element2IndexValueMap element2IndexValueMap = null;

public ConditionQuery(HugeType resultType) {
super(resultType);
Expand Down Expand Up @@ -142,6 +146,34 @@ public void resetConditions() {
this.conditions = new LinkedHashSet<>();
}

public void recordIndexValue(Id propertyId, Id id, Object indexValue) {
this.ensureElement2IndexValueMap();
this.element2IndexValueMap.addIndexValue(propertyId, id, indexValue);
}

public void selectedIndexField(Id indexField) {
this.ensureElement2IndexValueMap();
this.element2IndexValueMap.selectedIndexField(indexField);
}

public Set<LeftIndex> getElementLeftIndex(Id elementId) {
if (this.element2IndexValueMap == null) {
return null;
}
return this.element2IndexValueMap.getLeftIndex(elementId);
}

public void removeElementLeftIndex(Id elementId) {
if (this.element2IndexValueMap == null) {
return;
}
this.element2IndexValueMap.removeElementLeftIndex(elementId);
}

public boolean elementHasLeftIndex(Id elementId) {
return this.getElementLeftIndex(elementId) != null;
}

public List<Condition.Relation> relations() {
List<Condition.Relation> relations = new ArrayList<>();
for (Condition c : this.conditions) {
Expand Down Expand Up @@ -417,7 +449,6 @@ public boolean hasNeqCondition() {
return false;
}


public boolean matchUserpropKeys(List<Id> keys) {
Set<Id> conditionKeys = this.userpropKeys();
return keys.size() > 0 && conditionKeys.containsAll(keys);
Expand Down Expand Up @@ -455,13 +486,13 @@ public boolean test(HugeElement element) {
if (this.resultsFilter != null) {
return this.resultsFilter.apply(element);
}

boolean valid = true;
for (Condition cond : this.conditions()) {
if (!cond.test(element)) {
return false;
}
valid &= cond.test(element);
valid &= (this.element2IndexValueMap == null ||
this.element2IndexValueMap.validRangeIndex(element, cond));
}
return true;
return valid;
}

public void checkFlattened() {
Expand Down Expand Up @@ -530,6 +561,24 @@ public void registerResultsFilter(Function<HugeElement, Boolean> filter) {
}
}

public ConditionQuery originConditionQuery() {
Query originQuery = this.originQuery();
if (!(originQuery instanceof ConditionQuery)) {
return null;
}

while (originQuery.originQuery() instanceof ConditionQuery) {
originQuery = originQuery.originQuery();
}
return (ConditionQuery) originQuery;
}

private void ensureElement2IndexValueMap() {
if (this.element2IndexValueMap == null) {
this.element2IndexValueMap = new Element2IndexValueMap();
}
}

public static String concatValues(List<Object> values) {
List<Object> newValues = new ArrayList<>(values.size());
for (Object v : values) {
Expand Down Expand Up @@ -568,4 +617,149 @@ public enum OptimizedType {
INDEX,
INDEX_FILTER
}

public static final class Element2IndexValueMap {

private final Map<Id, Set<LeftIndex>> leftIndexMap;
private final Map<Id, Map<Id, Set<Object>>> filed2IndexValues;
private Id selectedIndexField;
jadepeng marked this conversation as resolved.
Show resolved Hide resolved

public Element2IndexValueMap() {
this.filed2IndexValues = new HashMap<>();
this.leftIndexMap = new HashMap<>();
}

public void addIndexValue(Id indexField, Id elementId,
Object indexValue) {
if (!this.filed2IndexValues.containsKey(indexField)) {
this.filed2IndexValues.put(indexField, new HashMap<>());
}
Map<Id, Set<Object>> element2IndexValueMap =
this.filed2IndexValues.get(indexField);
if (element2IndexValueMap.containsKey(elementId)) {
element2IndexValueMap.get(elementId).add(indexValue);
} else {
element2IndexValueMap.put(elementId,
Sets.newHashSet(indexValue));
}
}

public void selectedIndexField(Id indexField) {
this.selectedIndexField = indexField;
}

public Set<Object> removeIndexValues(Id indexField, Id elementId) {
if (!this.filed2IndexValues.containsKey(indexField)) {
return null;
}
return this.filed2IndexValues.get(indexField).get(elementId);
}

public void addLeftIndex(Id indexField, Set<Object> indexValues,
Id elementId) {
LeftIndex leftIndex = new LeftIndex(indexValues, indexField);
if (this.leftIndexMap.containsKey(elementId)) {
this.leftIndexMap.get(elementId).add(leftIndex);
} else {
this.leftIndexMap.put(elementId, Sets.newHashSet(leftIndex));
}
}

public Set<LeftIndex> getLeftIndex(Id elementId) {
return this.leftIndexMap.get(elementId);
}

public void removeElementLeftIndex(Id elementId) {
this.leftIndexMap.remove(elementId);
}

public boolean validRangeIndex(HugeElement element, Condition cond) {
// Not UserpropRelation
if (!(cond instanceof Condition.UserpropRelation)) {
return true;
}

Condition.UserpropRelation propRelation =
(Condition.UserpropRelation) cond;
Id propId = propRelation.key();
Set<Object> fieldValues = this.removeIndexValues(propId,
element.id());
if (fieldValues == null) {
// Not range index
return true;
}

HugeProperty<Object> hugeProperty = element.getProperty(propId);
if (hugeProperty == null) {
// Property value has been deleted
this.addLeftIndex(propId, fieldValues, element.id());
jadepeng marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

/*
* NOTE: If success remove means has correct index,
* we should add left index values to left index map
* waiting to be removed
*/
boolean hasRightValue = removeValue(fieldValues, hugeProperty.value());
if (fieldValues.size() > 0) {
this.addLeftIndex(propId, fieldValues, element.id());
}

/*
* NOTE: When query by more than one range index field,
* if current field is not the selected one, it can only be used to
* determine whether the index values matched, can't determine
* the element is valid or not
*/
if (this.selectedIndexField != null) {
return !propId.equals(this.selectedIndexField) || hasRightValue;
}

return hasRightValue;
}

private static boolean removeValue(Set<Object> values, Object value){
for (Object compareValue : values) {
if (numberEquals(compareValue, value)) {
values.remove(compareValue);
return true;
}
}
return false;
}

private static boolean numberEquals(Object number1, Object number2) {
// Same class compare directly
if (number1.getClass().equals(number2.getClass())) {
return number1.equals(number2);
}

// Otherwise convert to BigDecimal to make two numbers comparable
Number n1 = NumericUtil.convertToNumber(number1);
Number n2 = NumericUtil.convertToNumber(number2);
BigDecimal b1 = new BigDecimal(n1.doubleValue());
BigDecimal b2 = new BigDecimal(n2.doubleValue());
return b1.compareTo(b2) == 0;
}
}

public static final class LeftIndex {

private final Set<Object> indexFieldValues;
private final Id indexField;

public LeftIndex(Set<Object> indexFieldValues, Id indexField) {
this.indexFieldValues = indexFieldValues;
this.indexField = indexField;
}

public Set<Object> indexFieldValues() {
return indexFieldValues;
}

public Id indexField() {
return indexField;
}
}
}
Loading