-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[CALCITE-7427] Add connection config to enable RuleMatchVisualizer #4602
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
base: main
Are you sure you want to change the base?
Conversation
03007c4 to
008d47e
Compare
008d47e to
06288d4
Compare
06288d4 to
7cc21d1
Compare
|
| TOPDOWN_OPT("topDownOpt", Type.BOOLEAN, CalciteSystemProperty.TOPDOWN_OPT.value(), false), | ||
|
|
||
| /** Directory path for RuleMatchVisualizer output. | ||
| * If set, enables visualization of the rule matching process during query optimization. |
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.
does this enable visualization or just dumping the data to be visualized in a specific directory?
| * Utility class to enable RuleMatchVisualizer for Calcite connections. | ||
| * | ||
| * <p>This class provides hooks to automatically attach a RuleMatchVisualizer | ||
| * to planners when a connection specifies the ruleVisualizerDir property. |
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.
You use plural "planners". If there are multiple planners how are the visualizations for each of them distinguished? The output file name seems to be hardwired.
| // Enable visualizer | ||
| RuleMatchVisualizerHook.INSTANCE.enable(vizDir); | ||
|
|
||
| // Directory should be created |
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.
The hook should create the directory?
| assertThat(dataFiles, hasSize(1)); | ||
| assertThat(htmlFiles, hasSize(1)); | ||
| assertThat(dataFiles.get(0).getName(), containsString(DATA_FILE_PREFIX)); | ||
| assertThat(htmlFiles.get(0).getName(), containsString(HTML_FILE_PREFIX)); |
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.
should these files be deleted?
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.
JUnit takes care of this, see TempDir.
| * Attaches a visualizer to the given planner. | ||
| */ | ||
| private void attachVisualizer(RelOptPlanner planner, String outputDir) { | ||
|
|
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.
a few too many spaces around here
| */ | ||
| private void attachVisualizer(RelOptPlanner planner, String outputDir) { | ||
|
|
||
| // Check if we've already attached a visualizer to this planner |
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.
"we" is probably not appropriate.
|
|
||
| int queryNum = queryCounter.incrementAndGet(); | ||
| int queryStart = (int) System.currentTimeMillis() / 1000; | ||
| String suffix = String.format(Locale.ROOT, "query_%d_%d", queryNum, queryStart); |
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.
I see, the names are generated; this probably should be documented
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.
I would suggest using plan_%d_%d, as a query might be compiled in several stages and have multiple plans. As far as I know, Calcite does not provide a query id. Some projects that use Calcite may do, though, and I wonder whether there's an easy way to include this in the file name. The query id could be passed as a setter/getter on the RelOptPlanner.
| visualizer.attachTo(planner); | ||
| visualizerMap.put(planner, visualizer); | ||
|
|
||
| // For HepPlanner, we need to manually write the output |
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.
I am not sure what is "manual" here.
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.
A VolcanoPlanner will automatically write the output when its done with the planning. However, the writeToFile() needs to be called explicitly for a HepPlanner. So maybe explicitly would be a better word.
| hookCloseable.close(); | ||
|
|
||
| // Write any pending visualizations | ||
| for (RuleMatchVisualizer viz : visualizerMap.values()) { |
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.
I find it strange that "disable" causes writing.
Maybe the method should be called "close", or "flush", or the write calls should be moved somewhere else.
|
@tjbanghart, thank you for the PR! It makes it easier to use the RuleMatchVisualizer. |
|
|
||
| int queryNum = queryCounter.incrementAndGet(); | ||
| int queryStart = (int) System.currentTimeMillis() / 1000; | ||
| String suffix = String.format(Locale.ROOT, "query_%d_%d", queryNum, queryStart); |
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.
I would suggest using plan_%d_%d, as a query might be compiled in several stages and have multiple plans. As far as I know, Calcite does not provide a query id. Some projects that use Calcite may do, though, and I wonder whether there's an easy way to include this in the file name. The query id could be passed as a setter/getter on the RelOptPlanner.
| RuleMatchVisualizerHook.INSTANCE.enableFromConnection(this); | ||
| } catch (Exception e) { | ||
| // Log but don't fail connection if visualizer setup fails | ||
| System.err.println("Warning: Failed to enable RuleMatchVisualizer: " + e.getMessage()); |
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.
I would prefer using a LOGGER. Not sure whether a new method in org.apache.calcite.util.trace.CalciteTrace is needed, or whether a LOGGER can be defined as in org.apache.calcite.runtime.ResultSetEnumerable#LOGGER.
| visualizer.attachTo(planner); | ||
| visualizerMap.put(planner, visualizer); | ||
|
|
||
| // For HepPlanner, we need to manually write the output |
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.
A VolcanoPlanner will automatically write the output when its done with the planning. However, the writeToFile() needs to be called explicitly for a HepPlanner. So maybe explicitly would be a better word.
| // VolcanoPlanner automatically calls writeToFile() when done | ||
|
|
||
| System.out.println("RuleMatchVisualizer enabled: Output will be written to " | ||
| + outputDir + File.separator + suffix + "*"); |
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.
Please use a LOGGER here as well.
| /** | ||
| * Disables the visualizer. | ||
| */ | ||
| public synchronized void disable() { |
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.
The disable() should be called somewhere as well. The Handler defined in org.apache.calcite.jdbc.Driver#createHandler could override onConnectionClose to call it. I would strongly recommend to make the calls to "enable" and "disable" in the same class. So either moving the init code to Driver#createHandler as well, or creating another method in CalciteConnectionImpl to complement the init() method.
| * | ||
| * @param connection The Calcite connection | ||
| */ | ||
| public synchronized void enableFromConnection(CalciteConnection connection) { |
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.
The code in CalciteConnectionImpl already checks for an existing dir, so it could just call the enable method directly.
| assertThat(dataFiles, hasSize(1)); | ||
| assertThat(htmlFiles, hasSize(1)); | ||
| assertThat(dataFiles.get(0).getName(), containsString(DATA_FILE_PREFIX)); | ||
| assertThat(htmlFiles.get(0).getName(), containsString(HTML_FILE_PREFIX)); |
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.
JUnit takes care of this, see TempDir.
|
Thank you both for the reviews! I'll be able to revisit shortly. @thomasrebele since you're here, is there a way to highlight the cheapest path in the visualizer? If not is there an existing issue to add this functionality? |
|
@tjbanghart, could you explain what you mean by the cheapest path? I've got a draft to improve the visualizer. You can have a look at #4506. If you have ideas for improvement, feel free to add a comment to https://issues.apache.org/jira/browse/CALCITE-7133 or create a new ticket and tag me in a comment. The improvement has a feature to show a sub-graph connecting some specified nodes (and hiding all other nodes). Maybe that's close enough to your use case? |
|
This pull request has been marked as stale due to 30 days of inactivity. It will be closed in 90 days if no further activity occurs. If you think that’s incorrect or this pull request requires a review, please simply write any comment. If closed, you can revive the PR at any time and @mention a reviewer or discuss it on the [email protected] list. Thank you for your contributions. |



CALCITE-7247