2011-05-30 40 views
0

我正在定製Highlighter插件(使用FVH)來輸出給定搜索的查詢字詞的位置偏移量。到目前爲止,我已經能夠使用下面的代碼提取普通查詢的偏移量信息。然而,對於短語查詢,即使它不是短語查詢的一部分,代碼也會返回所有查詢詞的位置偏移量(即termSet)。因此,我想知道在Lucene中是否有方法僅使用FVH獲取短語查詢的匹配短語的偏移量信息?Lucene中短語查詢的位置偏移量

// In DefaultSolrHighlighter.java::doHighlightingByFastVectorHighlighter() 

SolrIndexSearcher searcher = req.getSearcher(); 
TermFreqVector[] tvector = searcher.getReader().getTermFreqVectors(docId); 
TermPositionVector tvposition = (TermPositionVector) tvector[0]; 

Set<String> termSet = highlighter.getHitTermSet (fieldQuery, fieldName); 

int[] positions; 
List hitOffsetPositions = new ArrayList<String[]>(); 

for (String term : termSet) 
{ 
    int index = tvposition.indexOf(term); 
    positions = tvposition.getTermPositions(index); 

    StringBuilder sb = new StringBuilder(); 
    for (int pos : positions) 
    { 
     if (!Integer.toString(pos).isEmpty()) 
      sb.append(pos).append(','); 
    } 
    hitOffsetPositions.add(sb.substring(0, sb.length() - 1).toString()); 
} 

if(snippets != null && snippets.length > 0) 
{ 
    docSummaries.add(fieldName, snippets); 
    docSummaries.add("hitOffsetPositions", hitOffsetPositions); 
} 


// In FastVectorHighlighter.java 
// Wrapper function to get query Terms 
    public Set<String> getHitTermSet (FieldQuery fieldQuery, String fieldName) 
    { 
     Set<String> termSet = fieldQuery.getTermSet(fieldName); 
     return termSet; 
    } 

電流輸出:

<lst name="6H500F0"> 
    <arr name="name"> 
    <str> New <em>hard drive</em> 500 GB SATA-300 and old drive 200 GB</str> 
</arr> 
<arr name="hitOffsetPositions"> 
    <str>2</str> 
    <str>3</str> 
    <str>10</str> 
</arr> 

預期輸出:

<lst name="6H500F0"> 
    <arr name="name"> 
    <str> New <em>hard drive</em> 500 GB SATA-300 and old drive 200 GB</str> 
</arr> 
<arr name="hitOffsetPositions"> 
    <str>2</str> 
    <str>3</str> 
</arr> 

,我想強調的領域有termVectors = 「真」termPositions =「true」termOffsets =「true」並且正在使用Lucene 3.1.0。

回答

0

我沒有能夠讓FVH正確處理短語查詢,並且不得不開發我自己的彙總程序。我的方法的要點在here;我最終做的是創建一個對象數組,我從查詢中提取每個術語的一個對象。每個對象都包含一個單詞索引及其位置,以及它是否已在某個匹配中使用。這些實例是以下示例中的TermAtPosition實例。然後,給定位置跨度和對應於短語查詢的單詞標識(索引)數組,我遍歷數組,查找與給定跨度內的所有項索引匹配。如果我找到匹配項,我將每個匹配項標記爲正在使用,並將匹配的跨度添加到匹配項列表中。然後我可以用這些比賽來評分句子。這裏是匹配的代碼:

protected void scorePassage(TermPositionVector v, String[] words, int span, 
        float score, SentenceScore[] scores, Scorer scorer) { 
    TermAtPosition[] order = getTermsInOrder(v, words); 
    if (order.length < words.length) 
     return; 
    int positions[] = new int[words.length]; 
    List<int[]> matches = new ArrayList<int[]>(); 
    for(int t=0; t<order.length; t++) { 
     TermAtPosition tap = order[t]; 
     if (tap.consumed) 
      continue; 

     int p = 0; 
     positions[p++] = tap.position; 
     for(int u=0; u<words.length; u++) { 
      if (u == tap.termIndex) 
       continue; 
      int nextTermPos = spanContains(order, u, tap.position, span); 
      if (nextTermPos == -1) 
       break; 
      positions[p++] = nextTermPos; 
     } 
     // got all terms 
     if (p == words.length) 
      matches.add(recordMatch(order, positions.clone())); 
    } 
    if (matches.size() > 0) 
     for (SentenceScore sentenceScore: scores) { 
      for(int[] matchingPositions: matches) 
       scorer.scorePassage(sentenceScore, matchingPositions, score); 
    } 
} 


protected int spanContains(TermAtPosition[] order, int targetWord, 
        int start, int span) { 
    for (int i=0; i<order.length; i++) { 
     TermAtPosition tap = order[i]; 
     if (tap.consumed || tap.position <= start || 
         (tap.position > start + span)) 
      continue; 
     if (tap.termIndex == targetWord) 
      return tap.position; 
    } 
    return -1; 
} 

這種方法似乎工作,但它是貪婪的。給定一個序列「a a b c」,它將匹配第一個a(離開第二個a),然後匹配b和c。我認爲可以使用一些遞歸或整數編程來使它不那麼貪婪,但是我不會感到困擾,並且想要一個更快而不是更準確的算法。

+0

這是否也適用於MultiPhraseQuery? – Jahangir 2011-05-31 21:12:34

+0

您必須知道哪些術語是變體(隱式「或」)以及哪些是匹配所需的。我會處理上述所需的條款;要處理變體(只有其中一個必須匹配),請更改spanContains()調用周圍的邏輯,該調用爲每個變體調用一次,並保持返回值接近所需的期限。 – 2011-06-01 01:04:16