You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@arrow.apache.org by "alamb (via GitHub)" <gi...@apache.org> on 2023/06/11 13:11:07 UTC

[GitHub] [arrow-datafusion] alamb opened a new issue, #6635: Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)`

alamb opened a new issue, #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635

   ### Is your feature request related to a problem or challenge?
   
   A user on slack was using datafusion to query parquet files from S3: https://the-asf.slack.com/archives/C01QUFS30TD/p1686147411917959
   
   They reported that the following predicate got 1000x slower when it had 100,000 distinct filter values:
   ```sql
   WHERE
   (rate.code = 'SC1' and rate.type = 'UT1' and rate.operation = 'RO1') 
   OR 
   (rate.code = 'SC2' and rate.type = 'UT2' and rate.operation = 'RO2')
   ...
   ```
   
   However, when it was rewritten as an inlist it went much faster:
   ```sql
   WHERE (rate.code || '_' || rate.type || '_' || rate.operation) IN ('SC1_UT1_RO1', 'SC2_UT2_RO2', ...)
   ```
   
   However, this rewrite is not general (for example, if `code`, `type` or `operation` contain `_` characters.
   
   SQL supports this type of predicate natively with "multi-column inlists" that look like;
   
   ```sql
   WHERE (rate.code,  rate.type, rate.operation) IN (('SC1', 'UT1', 'RO1'), ('SC2', 'UT2', 'RO2') ...)
   ```
   
    Substrait supports this kind of predicate too, which I take as some evidence it is widely used
   
   https://substrait.io/expressions/specialized_record_expressions/#or-list-equality-expression
   
   ```
   > A specialized structure that is often used is a large list of possible values. In SQL, these are typically large IN lists. They can be composed from one or more fields. There are two common patterns, single value and multi value. In pseudocode they are represented as:
   ```
   
   ### Describe the solution you'd like
   
   I would like multi-column predicates to work in DataFusion. 
   
   today, they result in an "unimplemented" error:
   
   ```sql
   ❯ create table foo (x int, y varchar);
   0 rows in set. Query took 0.001 seconds.
   ❯ insert into foo values (1, 'a'), (2, 'b'), (3, 'c');
   +-------+
   | count |
   +-------+
   | 3     |
   +-------+
   1 row in set. Query took 0.002 seconds.
   ❯ select * from foo where (x, y) IN ((1,'a'), (2, 'b'), (5, 'e'));
   This feature is not implemented: Unsupported ast node in sqltorel: Tuple([Value(Number("1", false)), Value(SingleQuotedString("a"))])
   ```
   
   Here is an example showing this feature working in posgres:
   
   ```sql
   postgres=# create table foo (x int, y varchar);
   CREATE TABLE
   postgres=# insert into foo values (1, 'a'), (2, 'b'), (3, 'c');
   INSERT 0 3
   postgres=# select * from foo;
    x | y
   ---+---
    1 | a
    2 | b
    3 | c
   (3 rows)
   postgres=# select * from foo where (x, y) IN ((1,'a'), (2, 'b'), (5, 'e'));
    x | y
   ---+---
    1 | a
    2 | b
   (2 rows)
   ```
   
   ### Describe alternatives you've considered
   
   The existing InList structure looks like this: https://docs.rs/datafusion-expr/26.0.0/datafusion_expr/expr/struct.InList.html
   
   ```rust
   pub struct InList {
       pub expr: Box<Expr>,
       pub list: Vec<Expr>,
       pub negated: bool,
   }
   ```
   
   I am not sure how best to implement this. One idea is to simply special case multi-inputs, something like 
   
   ```rust
   struct MultIInList {
       pub exprs: Vec<Expr>,
       pub lists: Vec<Vec<Expr>>,
       pub negated: bool,
   }
   ```
   
   However, my preferred approach would be to support `StructArray`s in `InList` and then implement a rewrite from
   
   ```sql
   (col1, col2, ...) in (('a1', 'a2', ..), ('b1', 'b2', ..), ...)
   ```
   into
   
   ```
   struct(col1, col2) In ({ col1: 'a', col2: 'a2', ..}, {col1: 'b1', col2: 'b2', ..}, ...)
   ```
   
   While likely more complicated this approach would then support structs in INLISTs directly which I think will be more and more valuable over time
   
   
   
   ### Additional context
   
   _No response_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1843704044

   > Tuple(Vec<Column>)
   
   Perhaps it could be represented like `ScalarValue::List(..)` 🤔 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow-datafusion] alamb commented on issue #6635: Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)`

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1590004849

   > We can add a new type of Expr called StructArrays
   
   I think we could also use the existing `ScalarValue` like this : https://docs.rs/datafusion/latest/datafusion/scalar/enum.ScalarValue.html#variant.Struct
   
   The trick in that case would be implementing `StructArray` support in https://github.com/apache/arrow-datafusion/blob/main/datafusion/physical-expr/src/expressions/in_list.rs  -- @tustvold  said on slack "it would be straightforward" 😆  which it might be for him, I don't think it would be a good first issue
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1846114004

   I think the idea is that 
   
   | col1 | col2 |
   |--------|--------|
   | A | 1 |
   | B | 2 |
   | C | 3 | 
   
   So a query like `SELECT * FROM t WHERE (col1, col2) IN (('A', 1), ('B', 2))`
   
   Rather than actually implementing a second dimension in `InExpr` we could potentially keep things simpler with a rewrite like this:
   
   ```
   SELECT * 
   FROM t 
   WHERE (struct(col1, col2)) IN (struct('A', 1)), struct ('B', 2))`
   ```
   
   Where the struct function does this:
   
   ```
   DataFusion CLI v33.0.0
   ❯ select struct('A', 1);
   +----------------------------+
   | struct(Utf8("A"),Int64(1)) |
   +----------------------------+
   | {c0: A, c1: 1}             |
   +----------------------------+
   ```
   
   This would likely be a much simpler implementation and would be faster than the chained or shown above
   
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "alamb (via GitHub)" <gi...@apache.org>.
alamb commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1847655478

   > But StructArray is not comparable in arrow-rs since it is nested. Should we implement compare in datafusion or upstream?
   
   I see your point. 
   
   The limitation appears to be in arrow itself: https://github.com/apache/arrow-rs/blob/7e289134a8d9f46a92a2759a7b2488b17993fd5b/arrow-ord/src/cmp.rs#L202-L204
   
   I think it might make sense to support equality of nested types upstream, though I am not sure about ordering comparsions (`<`, `<=`, etc)
   
   Perhaps it is worth filing a ticket in arrow-rs and proposing adding `StructArray` equality comparison support to eq and not_eq 🤔 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow-datafusion] mingmwang commented on issue #6635: Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)`

Posted by "mingmwang (via GitHub)" <gi...@apache.org>.
mingmwang commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1589701466

   I also prefer the `StructArrays` approach.  We can add a new type of `Expr` called  `StructArrays`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "my-vegetable-has-exploded (via GitHub)" <gi...@apache.org>.
my-vegetable-has-exploded commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1844407739

   > Perhaps it could be represented like `ScalarValue::List(..)` 🤔
   
   Sorry, maybe I don't get your point. I think ```(col1, col2, ...)``` likes multi-column projection from table rather than scalarvalue, so I don't think it can be be represented like ```ScalarValue::List(..)```.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "my-vegetable-has-exploded (via GitHub)" <gi...@apache.org>.
my-vegetable-has-exploded commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1846796006

   Thanks for your patience @alamb. After your explanation, I feel like I understand it a little bit more clearly.
   
   ```Tuple([Value('a'), Value('b)], ....)``` can be handled as ScalarValue(struct), ```struct(col1, col2)``` will be ```BuiltinScalarFunction::Struct``` whose args are col1 and col2 ...
   
   And in_list code is generalized.
   
   https://github.com/apache/arrow-datafusion/blob/c0c9e8888878c5d7f2586cf605702430c94ea425/datafusion/physical-expr/src/expressions/in_list.rs#L360-L363
   
   But StructArray is not comparable in arrow-rs since it is nested. Should we implement compare in datafusion or upstream?
   
   For example,
   
   ```
   ❯ CREATE TABLE colors (
       color_id INT PRIMARY KEY,
       color_name VARCHAR(50)
   );
   INSERT INTO colors (color_id, color_name) VALUES (1, 'Red'), (2, 'Blue');
   
   ❯ SELECT * FROM colors WHERE struct(color_id) IN (struct(arrow_cast(1,'Int32')));
   Arrow error: Invalid argument error: Invalid comparison operation: Struct([Field { name: "c0", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) == Struct([Field { name: "c0", data_type: Int32, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }])
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "my-vegetable-has-exploded (via GitHub)" <gi...@apache.org>.
my-vegetable-has-exploded commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1859198097

   https://github.com/apache/arrow-rs/blob/9a1e8b572d11078e813fffe3d5c7106b6953d58c/arrow-cast/src/cast.rs#L163-L164
   The cast between structarrays also needs to support, I think these are the inherent problems of nested types. I'd like complete this ticket when these are all done in upstream.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Support multi column IN lists like `(c1, c2) IN ((c1, c2), ,,,)` [arrow-datafusion]

Posted by "my-vegetable-has-exploded (via GitHub)" <gi...@apache.org>.
my-vegetable-has-exploded commented on issue #6635:
URL: https://github.com/apache/arrow-datafusion/issues/6635#issuecomment-1837509932

   I am interesting in this issue. But I'm not sure about some of the questions.
   
   - ```('a1', 'a2', ..)``` will be resolved as ```Tuple([Value('a'), Value('b)], ....)```, and ```(col1, col2, ...)``` will be ```Tuple([Identifier("col1"), Identifier("col1"), ......])```,  I don't know how represent ```Tuple(Vec<Column>)``` in logical_expr? Do we need to add a new type of Expr for it?
   
   > then implement a rewrite from
   - Does the Rewrite have a unified interface for that, or can I just write it where I want it to be ?
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org