public void insert(RankInfo[] rankInfoList, int n) throws IOException { if (n == 0) { return; } totalSearchCount += n; for (int k = 0; k < n; k++) { RankInfo ri = rankInfoList[k]; int docNo = ri.docNo(); indexRef.read(ri.docNo()); for (int i = 0; i < groupSize; i++) { if (fieldIndexRefList[i] != null) { fieldIndexRefList[i].read(docNo); } redundancyCheck.clear(); while (indexRef.getDataRef(i).next()) { // multi-value는 여러번.. BytesRef bytesRef = indexRef.getDataRef(i).bytesRef(); int groupNo = bytesRef.toIntValue(); for (GroupFunction groupFunction : groupFunctionList[i]) { if (groupFunction == null) { continue; } Number value = null; if (groupFunction.fieldId != null) { DataRef dataRef = fieldBytesRefMap[i].get(groupFunction.fieldId); dataRef.reset(); while (dataRef.next()) { value = dataRef.getNumber(); groupFunction.addValue(groupNo, value); } } else { // logger.debug("doc {} add group value groupNo={} val={}", docNo, groupNo, // value); groupFunction.addValue(groupNo, value); } } } } } }
protected boolean nextDoc(RankInfo docInfo) { if (termDocCollector == null) { termDocCollector = new TermDocCollector(termCount); } // 동일문서번호에 대한 TermDoc list를 리턴받는다. int docNo = -1; while (true) { while (true) { termDocCollector.clear(); docNo = termDocTreeReader.next(termDocCollector); if (docNo == -1 || (((float) termDocCollector.size()) / ((float) termDocCollector.capasity()) > 0.7f)) { break; } } if (docNo < 0) { return false; } else { // logger.debug(">> phrase doc={}, term size={}", docNo, // totalTermDocList.size()); // 쿼리와 비교한 여러단어에 대한 점수계산. if (storePosition) { float proximityScore = 0f; int documentScore = 0; float sumOfTPI = 0f; int windowSize = 2; // logger.debug("----------------------------{}", termDocCollector.size()); int continuosWords = 1; for (int i = 0; i < termDocCollector.size(); i++) { CollectedEntry entry = termDocCollector.get(i); PostingDoc termDoc = entry.termDoc(); // okapi점수에 tf만 사용. 쿼리점수무시. idf무시. // documentScore += (2.2f * (float)termDoc.tf() / (2.0f+ (float)termDoc.tf())); documentScore += 1; // logger.debug("[{}]doc >> {} : {} >> score {}", entry.term(), termDoc.docNo(), // termDoc.tf(), documentScore); // score += 1000; //tf 는 무시. 한단어가 여러번 나오는 것은 그다지 중요하지 // 않음. int[] positions = termDoc.positions(); // 인접해있는 windowSize 까지만 봄. int j = i + 1; if (j < termDocCollector.size()) { // TODO doc1과 doc2가 유사어관계면 점수계산하지 않는다. 근데 누구의 유사어인지 // 확인할 방법이없네.. // TODO 같은 단어를 두번이상 쿼리에 입려했을 경우 무시하는 로직 필요.? CollectedEntry entry2 = termDocCollector.get(j); PostingDoc termDoc2 = entry2.termDoc(); // logger.debug("### {}[{}] : {}[{}]", entry.term(), termDoc.tf(), // entry2.term(), termDoc2.tf()); int origianlPositionGap = entry2.queryPosition() - entry.queryPosition(); int[] positions2 = termDoc2.positions(); // logger.debug("pos1= {}", positions); // logger.debug("pos2= {}", positions2); int minGap = -1; for (int i2 = 0; i2 < positions.length; i2++) { for (int j2 = 0; j2 < positions2.length; j2++) { int actualPositionGap = positions2[j2] - positions[i2]; if (actualPositionGap > 10 || actualPositionGap < -10) { continue; } // logger.debug("------- {} - {} = {} : {}", positions[i2], // positions2[j2], actualPositionGap, origianlPositionGap); int gap = 0; if (origianlPositionGap > 0) { if (actualPositionGap > 0) { if (actualPositionGap <= origianlPositionGap + windowSize) { // logger.debug("OK"); gap = Math.abs(origianlPositionGap - actualPositionGap); } else { continue; } } else { if (-actualPositionGap <= origianlPositionGap) { // logger.debug("OK2"); gap = Math.abs(origianlPositionGap + actualPositionGap); } else { continue; } } } else { if (actualPositionGap > 0) { if (actualPositionGap <= -origianlPositionGap) { // logger.debug("OK3"); gap = Math.abs(-origianlPositionGap - actualPositionGap); } else { continue; } } else { if (-actualPositionGap <= -origianlPositionGap + windowSize) { // logger.debug("OK4"); gap = Math.abs(-origianlPositionGap + actualPositionGap); } else { continue; } } } if (minGap == -1 || gap < minGap) { minGap = gap; } } } if (minGap != -1) { continuosWords++; } // int positionGapDiff = origianlPositionGap - actualPositionGap; // d(ti, tj) = 원래차이 - 실제차이 => 원래차이와 실제차이가 // 같을수록 즉 0에 가까울수록 tpi가 높은 점수가 된다. // tpi(ti,tj) = 1.0 / d(t1, tj)^2 // 완벽한 TPRSV 점수를구하려면 문서길이/문서평균길이를 이용한 K 값을 // 계산해야 하나 여기서는 생략한다. float tpi = (float) (1.0 / (1.0 + Math.pow(minGap, 2.0))); // logger.debug("------- {} - {} = {} - {} = {} >> {}", // positions[i2], positions2[j2], // actualPositionGap, origianlPositionGap, // positionGapDiff, tpi); sumOfTPI += tpi; // logger.debug("{}: {} = {}",positions[i2], positions2[j2], tpi); } // if } /* * 인접을 보면서 제외시킨다. */ // logger.debug("####continuosWords {} >= {} ({})", continuosWords, (termCount/2) + 1, // termCount); if (continuosWords >= (termCount / 2) + 1) { float nomalizedDocScore = ((float) documentScore / (float) termCount) * 2.0f; // Okapi점수를 계산하여 tpi점수와 더해야 최종 점수가 계산됨. proximityScore = 2.2f * sumOfTPI / (2.0f + sumOfTPI); int score = (int) ((nomalizedDocScore + proximityScore) * SCORE_BASE); // logger.debug("nomalize {} = {} / {} * 2 => {} + {}", score, documentScore, // termCount, nomalizedDocScore, proximityScore); docInfo.init(docNo, score); break; } } else { // 위치정보가 없으면 tf를 점수로 만든다. // Okapi 점수 계산 float s = 0.0f; for (int i = 0; i < termDocCollector.size(); i++) { PostingDoc termDoc = termDocCollector.get(i).termDoc(); s += (2.2f * (float) termDoc.tf() / (2.0f + (float) termDoc.tf())); } int score = (int) (s * SCORE_BASE); logger.debug("추가2 >> docNo={} : {}", docNo, score); docInfo.init(docNo, score); break; } } } // TODO점수가 일정치이하이면 버린다. return true; }