[ 
https://issues.apache.org/jira/browse/PHOENIX-2160?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14715911#comment-14715911
 ] 

James Taylor commented on PHOENIX-2160:
---------------------------------------

Thanks for the patch, [~Dumindux]. I think we should kind of reverse the logic 
for this optimization in SelectClauseVisitor. Instead of optimizing array 
element references and then removing them if the array is referenced, let's 
leave the original ArrayIndexFunction in place, but do the reference counting 
you're doing now so that we know after the main loop in compile() whether or 
not we can do the optimization. That way we won't need to keep the old and new 
Expression as you've done in ArrayIndexExpression, but instead we'll generate 
the new expression after the main compile loop.  I think the only thing we'll 
need in the SelectClauseVisitor is your Map<ArrayIndexFunction, Integer> 
structure.

So after the loop in ProjectionCompiler.compile(), we'll have the following 
logic:
- Walk through the Map and remove any entry with a reference count > 0. The 
expressions remaining are the ones we can optimize.
- In this same loop, generate arrayKVFuncs and arrayKVFuncs.
- After this loop, call the function to push the info into the scan and 
generate the arrayIndexesBitSet and arrayIndexesSchema (but make them local 
variables as they're currently static which is a big no-no).
{code}
            if(arrayKVFuncs.size() > 0 && arrayKVRefs.size() > 0) {
                serailizeArrayIndexInformationAndSetInScan(context, 
arrayKVFuncs, arrayKVRefs);
                KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(0);
                for (Expression expression : arrayKVRefs) {
                    builder.addField(expression);
                }
                KeyValueSchema kvSchema = builder.build();
                ValueBitSet arrayIndexesBitSet = 
ValueBitSet.newInstance(kvSchema);
                builder = new KeyValueSchemaBuilder(0);
                for (Expression expression : arrayKVFuncs) {
                    builder.addField(expression);
                }
               KeyValueSchema arrayIndexesSchema = builder.build();
       }
{code}
- At the bottom of this if statement, add in code to create the new 
ArrayIndexExpression, passing through kvSchema and arrayIndexesSchema in the 
constructor. You'll want to track the old -> new mapping in a new 
Map<ArrayFunctionExpression, ArrayIndexExpression> (see below on why).
- Use a visitor to walk the tree for each projectedColumns expression and 
replaces any references to the the old ArrayFunctionExpression with the new 
ArrayIndexExpression. The easiest way to do this is to refactor 
CloneExpressionVisitor slightly by making an abstract method like 
isCloneNode(Expression node, List<Expression> children). This will replace the 
Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 checks. Then 
create a new concrete subclass called CloneNonDeterministicExpressionVisitor 
that implements isCloneNode() as return  
Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0. Use this new 
subclass in place of existing usages of CloneExpressionVisitor. Then, you'll 
create your own new concrete class called ReplaceArrayFunctionExpressionVisitor 
which will implement isCloneNode() something like the following (which will 
clone a tree with children that have changed or been replaced).
{code}
    return !children.equals(node.getChildren());
{code}
You'll also override visitLeave(ScalarFunction) as that's where you'll want to 
check your replacement map (which you'll pass through in a constructor):
{code}
 Expression replacement = replacementMap.containsKey(node);
 if (replacement != null) {
    return replacement;
 }
 return super.visitLeave(node,children);
{code}
Then you'll use this by instantiating a new 
ReplaceArrayFunctionExpressionVisitor(replacementMap) and doing a loop to 
replace each projectedColumns element with the return value of 
projectedColumn.accept(visitor).

One more minor item - I think you need to check that 
expression.getDataType().isArrayType() is true before incrementing your 
reference count here. Maybe add a reference to a non array column in your tests 
to improve coverage a bit.
{code}
+        @Override
+        public Expression visit(ColumnParseNode node) throws SQLException {
+            Expression expression = super.visit(node);
+            arrayExpressionCounts.put(expression, 
arrayExpressionCounts.containsKey(expression) ? 
(arrayExpressionCounts.get(expression) + 1) : 1);
+            return expression;
+        }
{code}

> Projection of specific array index does not work
> ------------------------------------------------
>
>                 Key: PHOENIX-2160
>                 URL: https://issues.apache.org/jira/browse/PHOENIX-2160
>             Project: Phoenix
>          Issue Type: Bug
>            Reporter: ramkrishna.s.vasudevan
>            Assignee: ramkrishna.s.vasudevan
>         Attachments: PHOENIX-2160.patch, PHOENIX-2160_v2.patch, 
> PHOENIX-2160_v3.patch, PHOENIX-2160_v4.patch, PHOENIX-2160_v5.patch
>
>
> PHOENIX-10 that allowed projection of specific array index does not work now. 
> Was looking into the code for some thing and found this issue. Let me know if 
> am missing something.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to