# Search for topics best matching a phrase (parent/child top\_children)

**URL:** <https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967>\
**Category:** Elasticsearch\
**Created:** [June 19, 2015, 6:09am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967 "2015-06-19T06:09:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![nyc863](https://avatars.discourse-cdn.com/v4/letter/n/a6a055/32.png) [@nyc863](https://discuss.elastic.co/u/nyc863)\
**Post date:** [June 19, 2015, 6:09am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/1 "2015-06-19T06:09:13Z")

</div>

I want a search that must be very common: return topics best suited to a search.

The topic document has the topic title (and perhaps other fields)  
The children docs are the posts in the topic, and they have several fields the most important is the post itself.

I don't want the search to return children individually, only parents.

I want to score the search by balancing topic title to a score relative to the post body.  
And the whole thing should be filterable on such things as date ranges, users post, message board name, etc (attributes of the children or attributes of the parent)

Having trouble getting this simple thing to work: to return only parents ordered by best match. based on their text and the text in their children....

---

<div class="post-metadata">

**Author:** ![dantuff](https://avatars.discourse-cdn.com/v4/letter/d/e79b87/32.png) [@dantuff](https://discuss.elastic.co/u/dantuff)\
**Post date:** [June 19, 2015, 10:06am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/2 "2015-06-19T10:06:13Z")

</div>

You'll need to use the [bool query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html) and combine a number `should` query clauses that contain queries to do what you want:

> [@nyc863](#):
>
> I don't want the search to return children individually, only parents

Use a [has\_child](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html) query to do this.

> [@nyc863](#):
>
> And the whole thing should be filterable on such things as date ranges, users post, message board name,

Use a [filtered query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html) for this, to filter on the child docs use the [has\_child](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-filter.html) filter.

> [@nyc863](#):
>
> I want to score the search by balancing topic title to a score relative to the post body.

You can `boost` individual query clauses, i.e., you could boost the topic title query clause higher than the others so that if a document matches on the title query it will be returned at the top of the results. Also, the `has_child` query has a `score_mode` parameter to help you tune the scoring.

If you're still having trouble getting it to work post the query you have so people can give pointers to help.

---

<div class="post-metadata">

**Author:** ![nyc863](https://avatars.discourse-cdn.com/v4/letter/n/a6a055/32.png) [@nyc863](https://discuss.elastic.co/u/nyc863)\
**Post date:** [June 20, 2015, 7:04am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/3 "2015-06-20T07:04:46Z")

</div>

I've tried two different approaches, neither satisfactory:

Here is one, the problem with this is if I order the matches by date not score, then it returns individual posts:  
 ![](https://us1.discourse-cdn.com/elastic/original/2X/a/ab1b98f15a648d26a8b45714469a3b1a75459589.png)

Another approach, the problem is it favours short topics (1 post) with single words that i'm searching for (highest hit to size ratio?). Also to make this work, I had to repeat the topic titles in the post document as another field (this screenshot is just of the inner part of the query, substituting for the inner part in the screenshot above):

![](https://us1.discourse-cdn.com/elastic/original/2X/a/a2ee26b556efa6d76ad58730281663cbdbcebb20.png)

You can infer the schema from these little queries, not that it is rocket science: topics are parent documents, just title and other attributes. Posts are child documents, body of post and title repeated if I want to waste that space...

EDIT; I changed "avg" to "sum" and now it (second solution) favours long topics with many children. I don't really like having to repeat the topic title field in the child however.

---

<div class="post-metadata">

**Author:** ![dantuff](https://avatars.discourse-cdn.com/v4/letter/d/e79b87/32.png) [@dantuff](https://discuss.elastic.co/u/dantuff)\
**Post date:** [June 22, 2015, 10:20am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/4 "2015-06-22T10:20:49Z")

</div>

> [@nyc863](#):
>
> I don't really like having to repeat the topic title field in the child however.

If you remove the `title` from the child doc and search on the `title` field in the parent document and the `note` field in the child document (as per your first example), the score from each query clause will be used to make up the overall score.

---

<div class="post-metadata">

**Author:** ![nyc863](https://avatars.discourse-cdn.com/v4/letter/n/a6a055/32.png) [@nyc863](https://discuss.elastic.co/u/nyc863)\
**Post date:** [June 23, 2015, 10:24am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/5 "2015-06-23T10:24:35Z")

</div>

thanks for the help.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 6, 2017, 12:06am UTC](https://discuss.elastic.co/t/search-for-topics-best-matching-a-phrase-parent-child-top-children/23967/6 "2017-07-06T00:06:00Z")

</div>


