The standard keyword recipe is BM25, short for Best Matching 25. Three rules drive it. Rare words count more: in 1,823 texts, a word found in 10 of them gets a weight of about 5.16, and a word found in 1,000 gets about 0.60. Repeats help, but less and less: with common settings, one use scores 1, two uses about 1.38, ten uses about 1.96, and it never passes 2.2. Long texts are scaled down, so length alone cannot win.
The two searches give scores on very different scales. In one test, the top BM25 score for a question was usually between about 13 and 53, while cosine scores sit between 0 and 1, so simply adding them lets BM25 decide almost everything. Reciprocal rank fusion (RRF) avoids this by using only each text's place in each list: add 1 / (60 + its keyword place) and 1 / (60 + its meaning place), then sort by the sum. The method and the constant 60 come from a 2009 paper by Cormack, Clarke and Buettcher.
A worked case. For "What does status 429 mean?", the text about HTTP 429 was first in both lists and scored 1/61 + 1/61 = 0.032787. A caching text, fourth by keywords and second by meaning, scored 1/64 + 1/62 = 0.031754. Because of the 60, one strong vote can beat two weak ones: first in one list and 60th in the other gives about 0.0247, which beats 30th in both, about 0.0222.