-
Notifications
You must be signed in to change notification settings - Fork 21
CNDB-13022: Fix analyzers for collections #1583
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -490,9 +490,17 @@ public boolean isSatisfiedBy(AbstractType<?> type, | |
| { | ||
| assert indexAnalyzer != null && queryAnalyzer != null : ": operation can only be computed by an indexed column with a configured analyzer"; | ||
|
|
||
| List<ByteBuffer> leftTokens = indexAnalyzer.analyze(leftOperand); | ||
| List<ByteBuffer> rightTokens = queryAnalyzer.analyze(rightOperand); | ||
| return isSatisfiedBy(type, leftOperand, rightTokens, indexAnalyzer); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isSatisfiedBy(AbstractType<?> type, | ||
| ByteBuffer leftValue, | ||
| List<ByteBuffer> rightTokens, | ||
| Index.Analyzer indexAnalyzer) | ||
| { | ||
| List<ByteBuffer> leftTokens = indexAnalyzer.analyze(leftValue); | ||
| Iterator<ByteBuffer> it = rightTokens.iterator(); | ||
|
|
||
| do | ||
|
|
@@ -641,6 +649,22 @@ public abstract boolean isSatisfiedBy(AbstractType<?> type, | |
| ByteBuffer rightOperand, | ||
| @Nullable Index.Analyzer indexAnalyzer, | ||
| @Nullable Index.Analyzer queryAnalyzer); | ||
| /** | ||
| * Whether 2 analyzable values satisfy this operator (given the type they should be compared with). | ||
| * | ||
| * @param type the type of the values to compare. | ||
| * @param leftOperand the left operand of the comparison. | ||
| * @param rightTokens the right operand of the comparison decomposed as analyzed tokens. | ||
| * @param indexAnalyzer an index-provided function to transform the left-side compared value before comparison, | ||
| * it shouldn't be {@code null}. | ||
| */ | ||
| public boolean isSatisfiedBy(AbstractType<?> type, | ||
| ByteBuffer leftOperand, | ||
| List<ByteBuffer> rightTokens, | ||
| Index.Analyzer indexAnalyzer) | ||
| { | ||
| throw new UnsupportedOperationException(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the record - Test coverage complains we don't cover this..... |
||
| } | ||
|
|
||
| public int serializedSize() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1260,22 +1260,28 @@ public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey partitionKey, | |
| private boolean contains(TableMetadata metadata, DecoratedKey partitionKey, Row row) | ||
| { | ||
| assert column.type.isCollection(); | ||
| CollectionType<?> type = (CollectionType<?>)column.type; | ||
| assert (indexAnalyzer == null) == (queryAnalyzer == null); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the assertion test coverage complains about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something that shouldn't happen given how the expressions are built (see here). I can only reproduce this by convoluted synthetic means which probably don't give too much value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion, the point of assertions is to test invariants that are not currently reachable but might become reachable in the future but that would break this code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Exactly, as mentioned in Slack I marked them mostly for history. |
||
|
|
||
| CollectionType<?> type = (CollectionType<?>) column.type; | ||
| List<ByteBuffer> analyzedValues = queryAnalyzer == null ? null : queryAnalyzer.analyze(value); | ||
|
|
||
| if (column.isComplex()) | ||
| { | ||
| ComplexColumnData complexData = row.getComplexColumnData(column); | ||
| if (complexData != null) | ||
| { | ||
| AbstractType<?> elementType = type.kind == CollectionType.Kind.SET ? type.nameComparator() : type.valueComparator(); | ||
| for (Cell<?> cell : complexData) | ||
| { | ||
| if (type.kind == CollectionType.Kind.SET) | ||
| ByteBuffer elementValue = type.kind == CollectionType.Kind.SET ? cell.path().get(0) : cell.buffer(); | ||
| if (analyzedValues == null) | ||
| { | ||
| if (type.nameComparator().compare(cell.path().get(0), value) == 0) | ||
| if (elementType.compare(elementValue, value) == 0) | ||
| return true; | ||
| } | ||
| else | ||
| { | ||
| if (type.valueComparator().compare(cell.buffer(), value) == 0) | ||
| if (Operator.ANALYZER_MATCHES.isSatisfiedBy(elementType, elementValue, analyzedValues, indexAnalyzer)) | ||
| return true; | ||
| } | ||
| } | ||
|
|
@@ -1285,37 +1291,35 @@ private boolean contains(TableMetadata metadata, DecoratedKey partitionKey, Row | |
| else | ||
| { | ||
| ByteBuffer foundValue = getValue(metadata, partitionKey, row); | ||
| if (foundValue == null) | ||
| return false; | ||
|
|
||
| switch (type.kind) | ||
| { | ||
| case LIST: | ||
| ListType<?> listType = (ListType<?>)type; | ||
| return listType.compose(foundValue).contains(listType.getElementsType().compose(value)); | ||
| case SET: | ||
| SetType<?> setType = (SetType<?>)type; | ||
| return setType.compose(foundValue).contains(setType.getElementsType().compose(value)); | ||
| case MAP: | ||
| MapType<?,?> mapType = (MapType<?, ?>)type; | ||
| return mapType.compose(foundValue).containsValue(mapType.getValuesType().compose(value)); | ||
| } | ||
| throw new AssertionError(); | ||
| return foundValue != null && Operator.CONTAINS.isSatisfiedBy(type, foundValue, value, indexAnalyzer, queryAnalyzer); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is so much better! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test coverage complains we cover 3 of 4 conditions only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason we cannot do a similar logical simplification in the |
||
| } | ||
| } | ||
|
|
||
| private boolean containsKey(TableMetadata metadata, DecoratedKey partitionKey, Row row) | ||
| { | ||
| assert column.type.isCollection() && column.type instanceof MapType; | ||
| MapType<?, ?> mapType = (MapType<?, ?>)column.type; | ||
| MapType<?, ?> mapType = (MapType<?, ?>) column.type; | ||
| if (column.isComplex()) | ||
| { | ||
| if (queryAnalyzer != null) | ||
| { | ||
| assert indexAnalyzer != null; | ||
| List<ByteBuffer> values = queryAnalyzer.analyze(value); | ||
| for (Cell<?> cell : row.getComplexColumnData(column)) | ||
| { | ||
| AbstractType<?> elementType = mapType.nameComparator(); | ||
| ByteBuffer elementValue = cell.path().get(0); | ||
| if (Operator.ANALYZER_MATCHES.isSatisfiedBy(elementType, elementValue, values, indexAnalyzer)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| return row.getCell(column, CellPath.create(value)) != null; | ||
| } | ||
| else | ||
| { | ||
| ByteBuffer foundValue = getValue(metadata, partitionKey, row); | ||
| return foundValue != null && mapType.getSerializer().getSerializedValue(foundValue, value, mapType.getKeysType()) != null; | ||
| return foundValue != null && Operator.CONTAINS_KEY.isSatisfiedBy(mapType, foundValue, value, indexAnalyzer, queryAnalyzer); | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new method can be used in a future improvement patch to cache the tokens of the right, fixed part of the operation in the calling
RowFilter.Expression. That way we wouldn't need to analyze that fixed part once and again for every evaluated row. I'm leaving that improvement out of this ticket so we can focus on fixing the correctness bug as soon as possible.