2011-07-12 14 views
3

検索を行う際に助けが必要です。 私は本当にシンプルな文書構造を持っていますが、名前の付いたフィールドは1つだけです。 長さが指定された値より大きいまたは小さいすべての名前を取得する必要があります。長さでは、私はString.length()を意味します。 レンジフィルタがコンセプトに近いようですが、具体的なケースを書く良い例が見つかりませんでした。 助けてくれてありがとう。Lucene:フィールドの値の長さによる検索/フィルタリング

+1

最も簡単な解決策は、長さを含む2番目のフィールドを作成することです。私は、 'name'フィールドのインデックスが、その長さで効率的にクエリするためにどのように使用できるのかよくわかりません。 – biziclop

+0

私はそのフィールドを作成し、インデックスを作成してから範囲フィルタ/クエリを実行することができたと思います。より直接的な解決策が必要だと私には思われますが、これは良い提案です。 – Federico

+0

もっと直接的な解決策があるかもしれませんが、私はLuceneのニューベーシストです(これが私の提案を答えではなくコメントとして書いた理由です)。しかしこれは確かに私がやることです。 – biziclop

答えて

2

長さを使用してNumericFieldを追加し、次にRangeQueryを使用します。例については、NumericField javadocを参照してください。

0

これは、MultiTermQueryの典型的な例です。それは箱の中ではなく、簡単に実装することができます。 MultiTermQueryを拡張するWildCardQueryをご覧ください。これは非常に似たようなことです。これと同じように、Term.textの長さを使用してターム(タームテキスト自体ではなく)をフィルタリングする、このような別のFilterredTermEnumを使用してください。上記のコードは、フィールドのすべての条項を通して見ると長さに対してその長さをチェックし

protected internal override bool TermCompare(Term term) 
{ 
    if (field == term.Field()) 
    { 
    System.String searchText = term.Text(); 
    if (searchText.Length >= text.Length()) 
    { 
     return true; 
    } 
    } 
    endEnum = true; 
    return false; 
} 

:マジックはここに起こる

が(このコードは私のポストの下部にあるカスタム用語列挙子です)コンストラクタで渡される用語のそれは、少なくともそれほど長いすべての分野で真実を発揮します。

public class MinLengthQuery : MultiTermQuery 
{ 
    public MinLengthQuery(Term term) : base(term) 
    { 
    } 

    protected internal override FilteredTermEnum GetEnum(IndexReader reader) 
    { 
    return new MinLengthTermEnum(reader, GetTerm()); 
    } 
} 

このクラスは、すべての作業を行います。

public class MinLengthTermEnum : FilteredTermEnum 
{ 
internal Term searchTerm; 
internal System.String field = ""; 
internal System.String text = ""; 
internal System.String pre = ""; 
internal int preLen = 0; 
internal bool endEnum = false; 

public MinLengthTermEnum(IndexReader reader, Term term):base() 
{ 
    searchTerm = term; 
    field = searchTerm.Field(); 
    text = searchTerm.Text(); 
    SetEnum(reader.Terms(new Term(searchTerm.Field(), ""))); 
} 

protected internal override bool TermCompare(Term term) 
{ 
    if (field == term.Field()) 
    { 
    System.String searchText = term.Text(); 
    if (searchText.Length >= text.Length()) 
    { 
     return true; 
    } 
    } 
    endEnum = true; 
    return false; 
} 

public override float Difference() 
{ 
    return 1.0f; 
} 

public override bool EndEnum() 
{ 
    return endEnum; 
} 
public override void Close() 
{ 
    base.Close(); 
    searchTerm = null; 
    field = null; 
    text = null; 
} 
} 

(私はlucene.net男だけど、翻訳は十分に簡単であることはず...おそらくで開始する方が簡単ですLuceneのWildCardQueryとTermEnumのソースコードのバージョンです。

+0

詳細な回答をいただきありがとうございます。それをjavaに変換することは、実際には簡単でした。 しかし、私は問題があると思います。これは、用語が列挙された基準によって順序付けされていることを前提としています。 インデックスは、次の内容を持っている場合: BBBB aaaabbbb AAAA ...とクエリが、これは第二要素で列挙停止し、第三を欠場するようにそれはそう5未満の長さを求めます。 endEnum()メソッドを調整して、return actualEnum.term()== nullを使用しました。それがうまくいくように見えるのは、索引検索をその検索語の線形検索に変えたようなものです。 – Federico

+0

私はそれを簡単なクエリと小さなデータベース(〜17kドキュメント)でテストし、この基準を追加するとクエリ時間が<10msから284msに変更されました。 長さフィールドとインデックスを追加できましたが、これは最初の提案に非常に近いものです。 あなたはどう思いますか? – Federico

+0

私はそれだけでなく、私が考えたことを理解していないように見えます。私はここのヒップから射撃していますが、正しいフィールドを見ているかどうかを確認するべきではありません。そうでなければ、次のフィールドに進むのですか?( 'actualEnum.term()。field()= = expectedField || actualEnum.term()== null')。私はTermEnumeratorが1つのフィールドから始まり、そのフィールドのすべての用語を調べ、次のフィールドに進み、最後のフィールドの最後の項に達すると考えました。 –

関連する問題