diff --git a/bigframes/core/compile/compiled.py b/bigframes/core/compile/compiled.py index 693d93de8c..6973091296 100644 --- a/bigframes/core/compile/compiled.py +++ b/bigframes/core/compile/compiled.py @@ -441,6 +441,10 @@ def explode(self, offsets: typing.Sequence[int]) -> UnorderedIR: columns=columns, ) + def as_ordered_ir(self) -> OrderedIR: + """Convert to OrderedIr, but without any definite ordering.""" + return OrderedIR(self._table, self._columns, predicates=self._predicates) + ## Helpers def _set_or_replace_by_id( self, id: str, new_value: ibis_types.Value diff --git a/bigframes/core/compile/compiler.py b/bigframes/core/compile/compiler.py index 23501f93c8..74fcaf5f2a 100644 --- a/bigframes/core/compile/compiler.py +++ b/bigframes/core/compile/compiler.py @@ -76,14 +76,27 @@ def _compile_node( @_compile_node.register def compile_join(self, node: nodes.JoinNode, ordered: bool = True): if ordered: - left_ordered = self.compile_ordered_ir(node.left_child) - right_ordered = self.compile_ordered_ir(node.right_child) - return bigframes.core.compile.single_column.join_by_column_ordered( - left=left_ordered, - right=right_ordered, - type=node.type, - conditions=node.conditions, - ) + # In general, joins are an ordering destroying operation. + # With ordering_mode = "partial", make this explicit. In + # this case, we don't need to provide a deterministic ordering. + if self.strict: + left_ordered = self.compile_ordered_ir(node.left_child) + right_ordered = self.compile_ordered_ir(node.right_child) + return bigframes.core.compile.single_column.join_by_column_ordered( + left=left_ordered, + right=right_ordered, + type=node.type, + conditions=node.conditions, + ) + else: + left_unordered = self.compile_unordered_ir(node.left_child) + right_unordered = self.compile_unordered_ir(node.right_child) + return bigframes.core.compile.single_column.join_by_column_unordered( + left=left_unordered, + right=right_unordered, + type=node.type, + conditions=node.conditions, + ).as_ordered_ir() else: left_unordered = self.compile_unordered_ir(node.left_child) right_unordered = self.compile_unordered_ir(node.right_child) diff --git a/bigframes/core/nodes.py b/bigframes/core/nodes.py index 2dc9623d89..93b59f75ee 100644 --- a/bigframes/core/nodes.py +++ b/bigframes/core/nodes.py @@ -249,6 +249,7 @@ def order_ambiguous(self) -> bool: @property def explicitly_ordered(self) -> bool: + # Do not consider user pre-join ordering intent - they need to re-order post-join in unordered mode. return False def __hash__(self): @@ -307,7 +308,8 @@ def order_ambiguous(self) -> bool: @property def explicitly_ordered(self) -> bool: - return all(child.explicitly_ordered for child in self.children) + # Consider concat as an ordered operations (even though input frames may not be ordered) + return True def __hash__(self): return self._node_hash