[ 
https://issues.apache.org/jira/browse/SOLR-18421?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Prithvi S updated SOLR-18421:
-----------------------------
    Description: 
Lucene 10.4 added {{ParentsChildrenBlockJoinQuery}}: matching children of 
matching parents, with an optional per-parent cap ({{childLimitPerParent}}). 
Solr is already on Lucene 10.4.0 and wraps {{ToParentBlockJoinQuery}} / 
{{ToChildBlockJoinQuery}} as {{!parent}} / {{!child}}, but never uses this 
class.

h3. Current behavior

{{!child}} takes a *parent* query and returns *all children* of those parents 
(optionally narrowed by {{childPath}}).

Child *filtering* is already possible outside the join, e.g.:

{code}
q=comments:lucene AND {!child parentPath="/"}title:solr
{code}

or via {{fq}} / {{childPath}}.

What is *not* possible today is applying a *per-parent child cap at query 
time*, especially together with a child query. A Boolean 
{{ToChildBlockJoinQuery}} + child query can filter children, but a limit 
applied by {{ToChildBlockJoinQuery}} first is not aware of the child query, so 
the intersection can be empty even when matching children exist. That is the 
Lucene 10.4 motivation (https://github.com/apache/lucene/issues/14565).

The {{[child]}} transformer's {{limit}} / {{childFilter}} params are *not* 
this: they decorate already-matched *parent* hits in the response. They do not 
change which documents the query matches.

h3. Proposed API (backward compatible)

Keep the existing {{!child}} body as the parent query. Add optional local 
params:

* {{childQuery}} — query over child documents
* {{childLimit}} — max matching children per parent (must be > 0)

{code}
q={!child parentPath="/" childQuery=$cq childLimit=2}title:solr
&cq=comments:lucene
{code}

Same params with the classic {{of}} form:

{code}
q={!child of="content_type:parent" childQuery=$cq childLimit=2}title:solr
&cq=comments:lucene
{code}

Omit *both* {{childQuery}} and {{childLimit}} → today's 
{{ToChildBlockJoinQuery}} (no behavior or scoring change).

When either param is set, use {{ParentsChildrenBlockJoinQuery}}:

* missing {{childQuery}} → {{MatchAllDocsQuery}} (cap all children of matching 
parents)
* missing {{childLimit}} → Lucene default {{Integer.MAX_VALUE}} (child query, 
no cap)
* {{childPath}} still applies: AND it onto the child query / returned children, 
same as today
* existing {{filters}} / {{excludeTags}} still apply to the *parent* clause, 
same as today

Hits remain *child documents only* (same as {{!child}} today). The Lucene class 
does not return parents.

h3. Scoring / stability notes

* Lucene default score is parent + child ({{Float::sum}}). Today's {{!child}} 
scores from the parent query only. Do not silently switch the no-param path to 
the new class.
* {{ParentsChildrenBlockJoinQuery}} is {{@lucene.experimental}}. Solr should 
treat {{childQuery}} / {{childLimit}} as experimental in the ref guide until 
Lucene marks the class stable (or Solr accepts the risk explicitly).
* v1 does not need to expose Lucene's custom {{scoreCombiner}}.

h3. Not in scope

* Changing {{[child]}} transformer behavior
* Returning parent+child pairs as hits
* A new query parser name

  was:
Lucene 10.4 added ParentsChildrenBlockJoinQuery 
(https://github.com/apache/lucene/issues/14565): match parent docs and child 
docs in the same block-join query, with an optional childLimitPerParent cap.
Solr already depends on Lucene 10.4.0 (gradle/libs.versions.toml) and already 
wraps ToParentBlockJoinQuery / ToChildBlockJoinQuery as \{!parent} / \{!child}, 
but never uses ParentsChildrenBlockJoinQuery.

*Current limitation*
{!child} takes a parent query and returns *all* children of those parents. 
There is no way to:
* also filter which children match
* cap the number of matching children per parent at *query* time
The [child] transformer \{{limit}} param is response decoration of 
already-matched parents, not a search-time limit.

*Proposed API (backward compatible)*
{code:java}
q=\{!child parentPath="/" childQuery=$cq childLimit=2}title:solr
&cq=comments:lucene
{code}

Omit childQuery/childLimit -> existing \{!child} behavior.


> {!child}: childQuery + per-parent childLimit via Lucene 
> ParentsChildrenBlockJoinQuery
> -------------------------------------------------------------------------------------
>
>                 Key: SOLR-18421
>                 URL: https://issues.apache.org/jira/browse/SOLR-18421
>             Project: Solr
>          Issue Type: New Feature
>          Components: query parsers
>            Reporter: Prithvi S
>            Priority: Major
>
> Lucene 10.4 added {{ParentsChildrenBlockJoinQuery}}: matching children of 
> matching parents, with an optional per-parent cap ({{childLimitPerParent}}). 
> Solr is already on Lucene 10.4.0 and wraps {{ToParentBlockJoinQuery}} / 
> {{ToChildBlockJoinQuery}} as {{!parent}} / {{!child}}, but never uses this 
> class.
> h3. Current behavior
> {{!child}} takes a *parent* query and returns *all children* of those parents 
> (optionally narrowed by {{childPath}}).
> Child *filtering* is already possible outside the join, e.g.:
> {code}
> q=comments:lucene AND {!child parentPath="/"}title:solr
> {code}
> or via {{fq}} / {{childPath}}.
> What is *not* possible today is applying a *per-parent child cap at query 
> time*, especially together with a child query. A Boolean 
> {{ToChildBlockJoinQuery}} + child query can filter children, but a limit 
> applied by {{ToChildBlockJoinQuery}} first is not aware of the child query, 
> so the intersection can be empty even when matching children exist. That is 
> the Lucene 10.4 motivation (https://github.com/apache/lucene/issues/14565).
> The {{[child]}} transformer's {{limit}} / {{childFilter}} params are *not* 
> this: they decorate already-matched *parent* hits in the response. They do 
> not change which documents the query matches.
> h3. Proposed API (backward compatible)
> Keep the existing {{!child}} body as the parent query. Add optional local 
> params:
> * {{childQuery}} — query over child documents
> * {{childLimit}} — max matching children per parent (must be > 0)
> {code}
> q={!child parentPath="/" childQuery=$cq childLimit=2}title:solr
> &cq=comments:lucene
> {code}
> Same params with the classic {{of}} form:
> {code}
> q={!child of="content_type:parent" childQuery=$cq childLimit=2}title:solr
> &cq=comments:lucene
> {code}
> Omit *both* {{childQuery}} and {{childLimit}} → today's 
> {{ToChildBlockJoinQuery}} (no behavior or scoring change).
> When either param is set, use {{ParentsChildrenBlockJoinQuery}}:
> * missing {{childQuery}} → {{MatchAllDocsQuery}} (cap all children of 
> matching parents)
> * missing {{childLimit}} → Lucene default {{Integer.MAX_VALUE}} (child query, 
> no cap)
> * {{childPath}} still applies: AND it onto the child query / returned 
> children, same as today
> * existing {{filters}} / {{excludeTags}} still apply to the *parent* clause, 
> same as today
> Hits remain *child documents only* (same as {{!child}} today). The Lucene 
> class does not return parents.
> h3. Scoring / stability notes
> * Lucene default score is parent + child ({{Float::sum}}). Today's {{!child}} 
> scores from the parent query only. Do not silently switch the no-param path 
> to the new class.
> * {{ParentsChildrenBlockJoinQuery}} is {{@lucene.experimental}}. Solr should 
> treat {{childQuery}} / {{childLimit}} as experimental in the ref guide until 
> Lucene marks the class stable (or Solr accepts the risk explicitly).
> * v1 does not need to expose Lucene's custom {{scoreCombiner}}.
> h3. Not in scope
> * Changing {{[child]}} transformer behavior
> * Returning parent+child pairs as hits
> * A new query parser name



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to