docs: double[][] BM25RelevanceMatixBuild(
              List<Sentence> sentence, List<List<IWord>> senWords)
      {
          int docNum = sentence.size();
          
          //1. count the average document length
          double avgdl = 0D;
          //for ( Sentence sen : sentence ) avgdl += sen.getLength();
          for ( List<IWord> words : senWords ) avgdl += words.size();
          avgdl /= docNum;
          
          //2. count all the tf and the df/N
          //word and the frequency mapping for each document 
          @SuppressWarnings("unchecked")
          Map<IWord, Integer>[] tf = new Map[docNum];
          //word and the number of document thats contains this word mapping 
          Map<IWord, Integer> df = new HashMap<IWord, Integer>();
          int index = 0;
          for ( List<IWord> words : senWords ) {
              Map<IWord, Integer> f = new HashMap<IWord, Integer>();
              for ( IWord word : words ) {
                  f.put(word, f.containsKey(word) ? f.get(word) + 1 : 1);
              }
              
              tf[index++] = f;
              
              /*
               * the logic inner the following loop could not merge in the above one
               * is because that same word may appear more than one time in a document,
               * well, map will clear up the duplicate. 
              */
              for ( Map.Entry<IWord, Integer> entry : f.entrySet() ) {
                  IWord key = entry.getKey();
                  df.put(key, df.containsKey(key) ? df.get(key) + 1 : 1);
              }
          }
          
          //3. count the words idf
          Map<IWord, Double> idf = new HashMap<IWord, Double>();
          for ( Map.Entry<IWord, Integer> entry : df.entrySet() ) {
              IWord key = entry.getKey();
              int nq = df.get(key).intValue();
              idf.put(key, Math.log((docNum - nq + 0.5) / (nq + 0.5)) );
          }
          
          //4. build the relevance score matrix
          double[][] scores = new double[docNum][docNum];
          for ( int i = 0; i < docNum; i++ ) {
              int j = 0;
              int dl = senWords.get(i).size();
              double dlRelative = K1 * (1 - B + B * dl / avgdl);
              
              /*
               * count the relevance for document sentence[i]
               * with all the queries sentence[i]  
              */
              for ( List<IWord> query : senWords ) {
                  double score = 0F;
                  for ( IWord q : query ) {
                      /*
                       * count the relevance of q with document sentence[i] 
                      */
                      int fi = tf[i].containsKey(q) ? tf[i].get(q).intValue() : 0;
                      double rel = fi * (K1 + 1) / (fi + dlRelative);
                      
                      /*
                       * count and add the sub relevance value: idf * rel 
                      */
                      score += idf.get(q).doubleValue() * rel;
                  }
                  
                  scores[i][j++] = score;
              }
          }
          
          //let gc do its work
          for ( Map<IWord, Integer> m : tf ) m.clear();
          tf = null;
          
          df.clear(); df = null;
          idf.clear(); idf = null;
          
          return scores;
      }