Repository: nomic-ai/gpt4all
File: gpt4all-chat/src/database.cpp (C++)

Code before:
    struct SearchResult { int chunkId; float dist; };
    QList<BM25Query> bm25Queries = queriesForFTS5(query);

    QList<SearchResult> results;
    for (auto bm25Query : bm25Queries) {
        QSqlQuery sqlQuery(m_db);
        sqlQuery.prepare(SELECT_CHUNKS_FTS_SQL.arg(k));
        sqlQuery.addBindValue(bm25Query.query);

        if (!sqlQuery.exec()) {
            qWarning() << "Database ERROR: Failed to execute BM25 query:" << sqlQuery.lastError();
            return {};
        }

        if (!sqlQuery.next())
            continue;

        bm25q = bm25Query;

        do {
            const int chunkId = sqlQuery.value(0).toInt();
            const float score = sqlQuery.value(1).toFloat();
            results.append({chunkId, score});
        } while (sqlQuery.next());
        break;
    }

    k = qMin(k, results.size());
    std::partial_sort(
        results.begin(), results.begin() + k, results.end(),
        [](const SearchResult &a, const SearchResult &b) { return a.dist < b.dist; }
    );

    QList<int> chunkIds;
    chunkIds.reserve(k);
    for (int i = 0; i < k; i++)
        chunkIds << results[i].chunkId;
    return chunkIds;
}

float Database::computeBM25Weight(const Database::BM25Query &bm25q)
{
    float bmWeight = 0.0f;
    if (bm25q.type == 0 /*exact*/) {
        bmWeight = 0.9f; // the highest we give
    } else {
        // qlength is the length of the phrases in the query by number of distinct words
        // ilength is the length of the natural language query by number of distinct words
        // rlength is the number of stop words removed from the natural language query to form the query
        float queryLengthWeight = powf(bm25q.qlength, 2) / powf(float(bm25q.ilength - bm25q.rlength), 2);
        queryLengthWeight = qBound(0.0f, queryLengthWeight, 1.0f);

Review comment (suggestion):
Since queriesForFTS5 is guaranteed to return at least one result, this could be more clearly written as:
```suggestion
        if (sqlQuery.next())
            break;
    }

    bm25q = bm25Query;

    do {
        const int chunkId = sqlQuery.value(0).toInt();
        const float score = sqlQuery.value(1).toFloat();
        results.append({chunkId, score});
    } while (sqlQuery.next());
```
as long as sqlQuery is declared before the loop.

Code after:

    std::stable_sort(
        results.begin(), results.end(),
        [&](const int &a, const int &b) {
            // Reciprocal Rank Fusion (RRF)
            const int aBm25Rank = bm25Ranks.value(a, bm25Results.size() + 1);
            const int aEmbeddingRank = embeddingRanks.value(a, embeddingResults.size() + 1);
            Q_ASSERT(embeddingRanks.contains(a));

            const int bBm25Rank = bm25Ranks.value(b, bm25Results.size() + 1);
            const int bEmbeddingRank = embeddingRanks.value(b, embeddingResults.size() + 1);
            Q_ASSERT(embeddingRanks.contains(b));

            const float aBm25Score = 1.0f / (fusion_k + aBm25Rank);
            const float bBm25Score = 1.0f / (fusion_k + bBm25Rank);
            const float aEmbeddingScore = 1.0f / (fusion_k + aEmbeddingRank);
            const float bEmbeddingScore = 1.0f / (fusion_k + bEmbeddingRank);
            const float aWeightedScore = bmWeight * aBm25Score + (1.f - bmWeight) * aEmbeddingScore;
            const float bWeightedScore = bmWeight * bBm25Score + (1.f - bmWeight) * bEmbeddingScore;

            // Higher RRF score means better ranking, so we use greater than for sorting
            return aWeightedScore > bWeightedScore;
        }
    );

    k = qMin(k, results.size());
    results.resize(k);
    return results;
}

QList<int> Database::searchDatabase(const QString &query, const QList<QString> &collections, int k)
{
    std::vector<float> queryEmbd = m_embLLM->generateQueryEmbedding(query);
    if (queryEmbd.empty()) {
        qDebug() << "ERROR: generating embeddings returned a null result";
        return { };
    }

    const QList<int> embeddingResults = searchEmbeddings(queryEmbd, collections, k);
    BM25Query bm25q;
    const QList<int> bm25Results = searchBM25(query, collections, bm25q, k);
    return reciprocalRankFusion(queryEmbd, embeddingResults, bm25Results, bm25q, k);
}

void Database::retrieveFromDB(const QList<QString> &collections, const QString &text, int retrievalSize,
    QList<ResultInfo> *results)
{
#if defined(DEBUG)
    qDebug() << "retrieveFromDB" << collections << text << retrievalSize;
#endif