0

基本的に他のクエリの加重合計であるクエリを作成しました。

val query = new BooleanQuery
for ((subQuery, weight) <- ...) {
  subQuery.setBoost(weight)
  query.add(subQuery, BooleanClause.Occur.MUST)
}

インデックスにクエリを実行すると、全体的なスコアを含むドキュメントが返されます。これは良いことですが、各サブクエリのサブスコアが何であったかを知る必要もあります。どうすれば入手できますか?これが私が今していることです:

for (scoreDoc <- searcher.search(query, nHits).scoreDocs) {
  val score = scoreDoc.score
  val subScores = subQueries.map { subQuery =>
    val weight = searcher.createNormalizedWeight(subQuery)
    val scorer = weight.scorer(reader, true, true)
    scorer.advance(scoreDoc.doc)
    scorer.score
  }
}

これで正しいスコアが得られると思いますが、全体のスコアの一部として既にスコアが付けられていることがわかっている場合に、ドキュメントに進んで再度スコアを付けるのは無駄に思えます。

これらのサブスコアを取得するより効率的な方法はありますか?

[私のコードは Scala で書かれていますが、Java の方が簡単な場合は自由に回答してください。]

編集: Robert Muir の提案に従った後、次のようになります。

クエリ:

val query = new BooleanQuery
for ((subQuery, weight) <- ...) {
  val weightedQuery = new BoostedQuery(subQuery, new ConstValueSource(weight))
  query.add(weightedQuery, BooleanClause.Occur.MUST)
}

検索:

val collector = new DocScoresCollector(nHits)
searcher.search(query, collector)
for (docScores <- collector.getDocSubScores) {
  ...
}

コレクター:

class DocScoresCollector(maxSize: Int) extends Collector {
  var scorer: Scorer = null
  var subScorers: Seq[Scorer] = null
  val priorityQueue = new DocScoresPriorityQueue(maxSize)

  override def setScorer(scorer: Scorer): Unit = {
    this.scorer = scorer
    // a little reflection hackery is required here because of a bug in
    // BoostedQuery's scorer's getChildren method
    // https://issues.apache.org/jira/browse/LUCENE-4261
    this.subScorers = scorer.getChildren.asScala.map(childScorer =>
      childScorer.child ...some hackery... ).toList
  }

  override def acceptsDocsOutOfOrder: Boolean = false

  override def collect(doc: Int): Unit = {
    this.scorer.advance(doc)
    val score = this.scorer.score
    val subScores = this.subScorers.map(_.score)
    priorityQueue.insertWithOverflow(DocScores(doc, score, subScores))
  }

  override def setNextReader(context: AtomicReaderContext): Unit = {}

  def getDocSubScores: Seq[DocScores] = {
    val buffer = Buffer.empty[DocScores]
    while (this.priorityQueue.size > 0) {
      buffer += this.priorityQueue.pop
    }
    buffer
  }
}

case class DocScores(doc: Int, score: Float, subScores: Seq[Float])

class DocScoresPriorityQueue(maxSize: Int) extends PriorityQueue[DocScores](maxSize) {
  def lessThan(a: DocScores, b: DocScores) = a.score < b.score
}
4

1 に答える 1

2

スコアラー ナビゲーション API があります。基本的な考え方は、コレクターを記述し、その setScorer メソッドで、通常はそのスコアラーへの参照を後でスコア() ヒットごとに保存することです。これで、そのスコアラーのサブスコアラーのツリーをたどることができます。すぐ。

スコアラーには、それらを作成した重みへのポインターと、クエリへの重みがあることに注意してください。

これらすべてを使用して、関心のあるサブスコアラーへの参照を setScorer メソッドで隠しておくことができます。たとえば、TermQueries から作成されたすべてのものです。次に、ヒットをスコアリングするときに、コレクター内のそれらのノードの freq() や score() などを調査できます。

3.x シリーズでは、これはブール関係に限定されたビジター API であり、4.x シリーズ (現在はアルファ リリースのみ) では、各サブスコアラーの子と関係を取得するだけなので、任意の関係で動作できます。クエリ (作成したカスタム クエリなどを含む)。

警告:

  • これを機能させるには、一度にドキュメントを処理する必要があるため、コレクターのacceptsDocsOutOfOrderからfalseを返す必要があります。
  • おそらく、3.6 シリーズのバグ修正ブランチ ( http://svn.apache.org/repos/asf/lucene/dev/branches/lucene_solr_3_6/ ) または 4.x のスナップショット ( http://svn.apache. org/repos/asf/lucene/dev/branches/branch_4x/ )。これは、論理和 (OR クエリ) が常にサブスコアラーを現在のドキュメントの '1 ドキュメント先' に設定するため、先週いくつかの問題が修正され、それらの修正が 3.6.1 に間に合わなかったため、この機能が一般的に機能しなかったためです。詳細については、 https://issues.apache.org/jira/browse/LUCENE-3505を参照してください。
  • すべてのリーフノードの用語頻度を合計するいくつかの簡単なテストを除いて、実際には良い例はありません (以下を参照)。

テスト:

于 2012-07-26T00:58:33.527 に答える