def bm25(raw_match_info, *args):
match_info = _parse_match_info(raw_match_info)<EOL>K = <NUM_LIT><EOL>B = <NUM_LIT><EOL>score = <NUM_LIT:0.0><EOL>P_O, C_O, N_O, A_O = range(<NUM_LIT:4>)  <EOL>term_count = match_info[P_O]  <EOL>col_count = match_info[C_O]<EOL>total_docs = match_info[N_O]  <EOL>L_O = A_O + col_count<EOL>X_O = L_O + col_count<EOL>weights = get_weights(col_count, args)<EOL>for i in range(term_count):<EOL><INDENT>for j in range(col_count):<EOL><INDENT>weight = weights[j]<EOL>if weight == <NUM_LIT:0>:<EOL><INDENT>continue<EOL><DEDENT>x = X_O + (<NUM_LIT:3> * (j + i * col_count))<EOL>term_frequency = float(match_info[x])  <EOL>docs_with_term = float(match_info[x + <NUM_LIT:2>])  <EOL>idf = math.log(<EOL>(total_docs - docs_with_term + <NUM_LIT:0.5>) /<EOL>(docs_with_term + <NUM_LIT:0.5>))<EOL>if idf <= <NUM_LIT:0.0>:<EOL><INDENT>idf = <NUM_LIT><EOL><DEDENT>doc_length = float(match_info[L_O + j])  <EOL>avg_length = float(match_info[A_O + j]) or <NUM_LIT:1.>  <EOL>ratio = doc_length / avg_length<EOL>num = term_frequency * (K + <NUM_LIT:1>)<EOL>b_part = <NUM_LIT:1> - B + (B * ratio)<EOL>denom = term_frequency + (K * b_part)<EOL>pc_score = idf * (num / denom)<EOL>score += (pc_score * weight)<EOL><DEDENT><DEDENT>return -score<EOL>
Usage:

    # Format string *must* be pcnalx
    # Second parameter to bm25 specifies the index of the column, on
    # the table being queries.
    bm25(matchinfo(document_tbl, 'pcnalx'), 1) AS rank