4

友達、

私はLuceneを初めて使用しています...
インデックスの作成、フィールドの追加、検索などに成功しました。

現在、データベースに、どのユーザーがどのドキュメントを表示できるかを示すビューがあります。このビューはいくつかの複雑なルールを使用して作成されているため、ビューを再利用したいと考えています。そのため、Lucene 検索にフィルターを追加して、クエリに一致するがユーザーがアクセスできないドキュメントを削除する必要があります。
私が今やろうとしたことは次
のとおりです。 - dbドキュメントIDをフィールドに保存します。これは Guid です。文字列として保存します。
- 現在のユーザーがアクセスできるすべてのドキュメント ID を取得するカスタム フィルターを作成し、lucene のフィールドを使用してフィルター処理する

効率的ではないと感じています... ユーザーは何十万ものドキュメントにアクセスできるため、フィルター処理が必要な 200,000 ドキュメント ID を取得できます。いくつかのものをキャッシュする必要があると思います...
ここに私が書いたコードがありますが、機能しません:フィルターが使用されたときにドキュメントが返されません(3つのドキュメントが返されるはずです)

public class LuceneAuthorisationFilter : Filter
{
    public override DocIdSet GetDocIdSet(Lucene.Net.Index.IndexReader reader)
    {
        List<Guid> ids = this.load(); // Load list of ID from database
        OpenBitSet result = new OpenBitSet(reader.MaxDoc);

        int[] docs = new int[1];
        int[] freq = new int[1];

        for (int i = 0; i < ids.Count; i++)
        {
            Lucene.Net.Index.TermDocs termDocs = reader.TermDocs(new Lucene.Net.Index.Term("EmId", ids.ElementAt(i).ToString()));

            int count = termDocs.Read(docs, freq);
            if (count == 1)
            {
                result.FastSet(docs[0]);
            }
        }
        return result;
    }
}

何が悪いのか分かりますか?そして、どのようにパフォーマンスを向上させますか?

ありがとうございました

編集:
上記のコードは機能しますが、問題は EmId フィールドがインデックス化されていないことだけでした。今、私は変わりました、そしてそれはうまくいきます。
今、私はパフォーマンスを向上させるためのヒントがあればいいのにと思います


フィードバックを追加するための 2 回目の編集

注: テスト環境には 25,000 のドキュメントが含まれており、ドキュメント アクセスのリストには 50,000 の ID が含まれています (すべてのドキュメントがまだ公開されていないため)。

インデックス付き)

  • 上記のカスタム フィルターを使用: フィルターがキャッシュされるため、初回は ~2600 ミリ秒、次回は 2100 ミリ秒
  • ブールクエリフィルターを使用: ~4700ms から ~4000ms

これらはパフォーマンスが悪いです...そこで、見つかった「FieldCacheTermsFilter」フィルターを再度検索しました。

  • FieldCacheTermFilter の使用: ~600ms から ~60ms

これは許容できるパフォーマンスです

PS:別の同様の質問も見つけました

4

1 に答える 1

3

数値/測定値が与えられていない場合、パフォーマンスについて話すことは常に難しい.

そうは言っても、パフォーマンスに関しては何をベンチに置いていますか? ボトルネック (IO/CPU/etc) は何ですか?他の方法と比較しましたか?

本当にパフォーマンスを向上させる必要がありますか? パフォーマンスの改善に関する議論は、「感情」に関するものではなく、証拠に基づく確固たる事実と改善の必要性に関するものです。

さてFilter、質問から得られなかったことがない限り、Lucene に既に組み込まれているものを使用して難しい作業を行うことができない理由がわかりません。

これは、私が Lucene でアクセス許可を処理する方法です。これは、何十億ものドキュメントを含むインデックスで常にうまく機能しました。私は通常、アイテムがキャッシュから消去されるように、最小有効期間を持つ LRU タイプのキャッシュを使用します。

IE: 100 個のアイテムをキャッシュしますが、使用頻度が最も低いものが 15 分以内であれば、より多くのアイテムをキャッシュします。

このようなことを試してみたら、それをあなたの方法と比較して、パフォーマンスの数値を投稿するために戻ってくると面白いかもしれません.

免責事項: SO のテキストエリアに直接記述されたコードは、既に動作しているコピー ペースト ソリューションよりも疑似コードとして使用します。

// todo: probably some thread safety
public class AccessFilterFactory
{
    private static AccessFilterFactory _instance = new AccessFilterFactory();;
    private AccessFilterFactory()
    {
    }

    public AccessFilterFactory Instance
    {
        get
        {
            return _instance;
        }
    }

    private Cache<int, Filter> someKindaCache = new Cache<int, Filter> ();

    // gets a cached filter if already built, if not it creates one
    // caches it and returns it
    public Filter GetFilterForUser(int userId)
    {
        // return from cache if you got it
        if(someKindaCache.Exists(userId))
            return someKindaCache.Get(userId);

        // if not, build and cache it
        BooleanQuery filterQuery = new BooleanQuery();
        foreach(string id in ids)
        {
            filterQuery.Add(new TermQuery(new Term("EmId", id)),  BooleanClause.Occur.SHOULD);
        }
        Filter cachingFilter = new CachingWrapperFilter(new QueryWrapperFilter(filterQuery));
        someKindaCache.Put(userId, cachingFilter);
        return cachingFilter;
    }

    // removes a new invalid filter from cache (permissions changed)
    public void InvalidateFilter(int userId)
    {
        someKindaCache.Remove(userId);
    }   
}
于 2013-04-08T14:00:29.810 に答える