Lucene中短语查询的位置偏移量

问题描述

| 我正在自定义Highlighter插件(使用FVH)以输出给定搜索查询词的位置偏移。到目前为止,我已经能够使用下面的代码提取常规查询的偏移信息。但是,对于短语查询,即使它不是短语查询的一部分,代码也会返回所有查询词(即termSet)的位置偏移量。因此,我想知道在Lucene中是否有一种方法可以仅使用FVH来获取短语查询的匹配短语的偏移信息?
// 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 = \“ true \”,termPositions = \“ true \”和termOffsets = \“ true \”,并且正在使用Lucene 3.1.0。     

解决方法

        我无法获得FVH来正确处理短语查询,因此不得不开发自己的摘要程序。我的方法要点在这里讨论。我最后要做的是创建一个对象数组,每个对象都是我从查询中提取的。每个对象都包含一个单词索引及其位置,以及它是否已在某些匹配中使用。这些实例是以下示例中的“ 3”个实例。然后,给定位置范围和与短语查询相对应的单词标识(索引)数组,我遍历该数组,以匹配给定范围内的所有术语索引。如果找到匹配项,则将每个匹配项标记为已消耗,并将匹配范围添加到匹配项列表中。然后,我可以使用这些匹配项来对句子评分。这是匹配的代码:
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。我认为可以应用一些递归或整数编程来减少它的贪婪性,但是我不为所动,并且无论如何都希望有一种更快而不是更精确的算法。