1

私は Grails 用の検索可能なプラグインを使用しています (Compass 用の API を提供し、それ自体が Lucene 上の API です)。検索したい Order クラスがありますが、 Order のすべてのインスタンスを検索するのではなく、それらのサブセットのみを検索します。このようなもの:

// This is a Hibernate/GORM call
List<Order> searchableOrders = Customer.findAllByName("Bob").orders

// Now search only these orders with the searchable plugin - something like
searchableOrders.search("name: foo")

実際には、searchableOrders を取得するためのリレーショナル クエリはこれよりも複雑なので、クエリ全体 (Hibernate + コンパス) をコンパスだけで実行することはできません。Compass/Lucene を使用して、特定のクラスのインスタンスのサブジェクトのみを検索する方法はありますか。

4

2 に答える 2

4

これを行う 1 つの方法は、カスタム フィルターを使用することです。たとえば、ドメイン クラスの ID に基づいてフィルタリングする場合は、ドメイン クラスの検索可能な構成に ID を追加します。

static searchable = {
   id name: "id"
}

次に、カスタム フィルターを記述します ([project]/src/java に入れることができます)。

import org.apache.lucene.search.Filter;
import java.util.BitSet;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexReader;

import java.io.IOException;
import java.util.List;

public class IdFilter extends Filter {

    private List<String> ids;

    public IdFilter(List<String> ids) {
        this.ids = ids;
    }

    public BitSet bits(IndexReader reader) throws IOException {
        BitSet bits = new BitSet(reader.maxDoc());
        int[] docs = new int[1];
        int[] freqs = new int[1];
        for( String id : ids ) {
            if (id != null) {
                TermDocs termDocs = reader.termDocs(new Term("id", id ) );
                int count = termDocs.read(docs, freqs);
                if (count == 1) {
                    bits.set(docs[0]);
                }
            }
        }
        return bits;
    }
}

次に、フィルターを検索の引数として配置します (別のパッケージにある場合は、Filter クラスをインポートするようにしてください)。

def theSearchResult = MyDomainClass.search( 
{
    must( queryString(params.q) )       
}, 
params,
filter: new IdFilter( [ "1" ] ))

ここでは、"1" という単一の値を含むハードコードされたリストを作成しているだけですが、データベースから、以前の検索から、またはどこからでも ID のリストを取得できます。

コンストラクターで用語名を取得し、必要に応じて「名前」を渡す必要があるフィルターを簡単に抽象化できます。

于 2010-01-27T14:21:05.503 に答える
2

これを行う 2 つの方法:

実装の観点から最も簡単なのは、すべてのオブジェクトに対して 2 つの検索 (1 つの findAll と検索) を実行してから、それらの間の共通点を見つけることです。findAll 呼び出しの結果をキャッシュすると、作成する必要があるクエリは 1 つになります。

これを行うためのより「クリーンな」方法は、ドメイン オブジェクトの ID を Searchable でインデックス付けし、findAll の結果が得られたら、それらの ID を検索クエリに渡して制限することです。

頭のてっぺんからLuceneの構文を覚えていませんが、次のようなことをする必要があります

searchableOrders.search("name: foo AND (ID:4 or ID:5 or ID:8 ...)" )

Lucene ではクエリ サイズの制限に遭遇する場合がありますが、クエリの長​​さを制御できる設定があると思います。

于 2009-11-27T20:19:07.603 に答える