docs: def bm25(raw_match_info, *args):
      """
      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
      """
      match_info = _parse_match_info(raw_match_info)
      K = 1.2
      B = 0.75
      score = 0.0
  
      P_O, C_O, N_O, A_O = range(4)  # Offsets into the matchinfo buffer.
      term_count = match_info[P_O]  # n
      col_count = match_info[C_O]
      total_docs = match_info[N_O]  # N
      L_O = A_O + col_count
      X_O = L_O + col_count
  
      weights = get_weights(col_count, args)
  
      for i in range(term_count):
          for j in range(col_count):
              weight = weights[j]
              if weight == 0:
                  continue
  
              x = X_O + (3 * (j + i * col_count))
              term_frequency = float(match_info[x])  # f(qi, D)
              docs_with_term = float(match_info[x + 2])  # n(qi)
  
              # log( (N - n(qi) + 0.5) / (n(qi) + 0.5) )
              idf = math.log(
                      (total_docs - docs_with_term + 0.5) /
                      (docs_with_term + 0.5))
              if idf <= 0.0:
                  idf = 1e-6
  
              doc_length = float(match_info[L_O + j])  # |D|
              avg_length = float(match_info[A_O + j]) or 1.  # avgdl
              ratio = doc_length / avg_length
  
              num = term_frequency * (K + 1)
              b_part = 1 - B + (B * ratio)
              denom = term_frequency + (K * b_part)
  
              pc_score = idf * (num / denom)
              score += (pc_score * weight)
  
      return -score