Repository navigation
feat: Facet on a field of nested children with child_facet, counting their parents - #10
Merged
Merged
Conversation
…g their parents Issue: a search could filter parents by their children (`with_child`) and sort by them (`order_by_child`), but not facet on a child field. Listing the values the children of the matching parents have, for example to suggest the next value of a nested filter, needed one: restricted to the children meeting the filter's other conditions, and counting parents rather than children. `child_facet :association, :field` adds a JSON terms facet whose domain is the `blockChildren` of the matching parents, filtered by the same restrictions `with_child` builds from the block (`BlockJoin#child_query`, now public). A `uniqueBlock(_root_)` sub-facet named `distinct` makes each row count parents, which `JsonFacetRow` already reads. `:matches` adds a Lucene regular expression the child's value must match. It needs Solr 8 and above for `uniqueBlock`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Root cause: `Query::AbstractJsonFieldFacet#to_params` calls `to_json` on the facet's params without requiring `json`, so building a JSON facet raised `NoMethodError` unless something else had loaded JSON first. The integration specs passed only because RSolr loads it, and no API spec built a JSON facet's params. `abstract_json_field_facet.rb` now requires `json` itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reject options it can't honour Root cause: a review of `child_facet` found that it reported each value's number of parents, but Solr still ranked, limited and applied a minimum count to the values by their number of children, so `:limit` could keep a value few parents have. It was keyed by its field's name in both the request and the response, so a `json_facet` or a second `child_facet` on a same-named field overwrote it, and `:name` didn't help. It silently ignored `json_facet` options it doesn't build, such as `:range`, `:distinct` and `:nested`, raised `NoMethodError` for a Ruby `Regexp` in `:matches`, and returned nothing for `:matches` on a field that isn't a string. It also claimed to need Solr 8, but Solr 7.7 has `uniqueBlock`. `child_facet` now sorts by the parent count unless sorted by `:index`, applies `:minimum_count` to parents when reading its rows (a new `Search::ChildFieldJsonFacet`, whose rows keep Solr's order), and is keyed by its `:name` or its field's name, raising `ArgumentError` when the search already has a facet by that name. It takes only the options it honours, and raises for anything else, for `:matches` that isn't a String or is on a field that isn't a string. `Sunspot::Util.escape_lucene_regexp` escapes text for `:matches`. API specs cover the request it builds, and the README gives it its own section, which states the Solr version and that `:matches` on a multiple-value field selects children, so a matching child's other values are counted too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
child_facet: a facet on a field of nested children that counts their parents. A search can already filter parents by their children (with_child) and sort by them (order_by_child). This adds the missing piece: listing the values the children of the matching parents have, restricted to the children meeting some conditions. The use it's built for is suggesting the next value of a nested filter in Glint's search autocomplete.What changes
DSL::FieldQuery#child_facet(association, field, options = {}, &block)adds a JSON terms facet:blockChildrenof the parents matching the search.with_childbuilds from the block.BlockJoin#child_queryis now public so both use one definition.uniqueBlock(_root_)sub-facet nameddistinctmakes each row count parents.JsonFacetRowalready reads adistinctsub-facet as the row's count.:matcheskeeps only the children whose value matches a Lucene regular expression as a whole. JSON facets have nofacet.matches, so it goes in the domain filter. The otherjson_facetoptions apply too.facet, by the field's name or by:name.order_by_child.Solr 8 and above, for
uniqueBlock. The new examples skip on older Solr, as theorder_by_childexamples do. I chose 8 as the cut-off, but only tested 9.10.1.Testing
spec/integration/nested_documents_spec.rb::matches, including a pattern containing a slash.uniqueBlocksub-facet, a project with two "build" milestones counts 3 instead of 2.sunspotsuite againstsolr:9.10.1withci/solr9: 1,542 examples, 0 failures, 6 pending.Draft until the Glint autocomplete work that uses it is ready.
🤖 Generated with Claude Code