1

Let's say I have 2 documents in my MongoDB database:

Document 1:

title: "elephant is an elephant"
description: "this elephant is an elephant"

Document 2:

title: "duck"
description: "duck is not an elephant"

How can I make Atlas search give both these results the same search score for "elephant"? I want it to only look for a keyword once and not weight the result higher if the keyword appears more often.

Note: Matches of different words should still rank higher than matching a single word. When the user searches for “duck elephant”, document 2 should be listed higher because it matches both words.

Florian Walther
  • 6,237
  • 5
  • 46
  • 104
  • 1
    Might not be exactly what you need but the most straight forward way is using constant score modifier. see docs: https://www.mongodb.com/docs/atlas/atlas-search/scoring/#constant – Oren Jul 22 '22 at 22:15
  • @Oren The problem with this is that I still want to score results higher that contain **different** words from the search query. With this approach the score will be fixed, no matter how many words match (if I understand it correctly) – Florian Walther Jul 22 '22 at 22:19
  • Your understanding is correct, try to use the `indexOption: docs` in your index definition with regards to the `title` and/or `description` field. The docs say this: > The frequency and position of the indexed term are ignored. Only a single occurence of the term is reflected in the score. docs: https://www.mongodb.com/docs/atlas/atlas-search/define-field-mappings/#string – Oren Jul 22 '22 at 22:38
  • @Oren That sounds exactly like what I need. I will try it out and report back! – Florian Walther Jul 23 '22 at 07:12
  • @Oren This will still rank results higher where the term appears in multiple different fields, right? I want to count it only once throughout the whole document. – Florian Walther Jul 23 '22 at 07:33
  • @Oren I think I can go with your initial idea of using a constant value, but add a separate entry for each word in the search query dynamically. What do you think? – Florian Walther Jul 23 '22 at 07:49

1 Answers1

0

The problem with a constant score is that I want to score results higher if multiple search terms fit, while only weighting each individual term exactly once.

I achieved my desired outcome by dynamically adding entries to the search compound operator for each search term, each having a constant search score.

Here is the code (simplified). searchTerms is my input query turned into a string array.

const shouldQueries = searchTerms.map(searchTerm: string) => ({
    wildcard: {
        query: searchTerm,
        path: ['title', 'description'],
        allowAnalyzedField: true,
        score: { constant: { value: 1 } }
    }
}));

let aggregation = Resource.aggregate()
    .search({
        compound: {
            must: [...],
            should: [...shouldQueries]
        }
    })

This should now weight each search term exactly once, no matter if it's found in the title or the description.

Florian Walther
  • 6,237
  • 5
  • 46
  • 104