ContentSearch APIで常に真になる条件の生成方法とその使い道
tackme
Posted on February 18, 2020
以下のコードで常に真になる条件の作成することができます。
var truePred = PredicateBuilder.Create<SearchResultItem>(item => item.Name.MatchWildcard("*"));
_name
フィールドは全てのドキュメントが持っているので、この条件は常に真(全てのドキュメントにヒットする)になります。あまりリーダブルではないので、コメントで補足するかラップしたメソッドを用意することをおすすめします。
一見以下のコードでもうまく動きそうですが、単体で使用すると例外が発生する上に、ORで連結すると条件が無視されてしまうため期待した動作にはなりません。
// うまく動かない例
var truePred1 = PredicateBuilder.True<SearchResultItem>();
var truePred2 = PredicateBuilder.Create<SearchResultItem>(item => true);
使い道
検索結果に重み付けを行う
「{常に真になる条件} OR {重み付けのための条件}
」でフィルターをかけることで、検索結果に重みをつけることができます。
以下の例では、Contentフィールドに"Foo"を含むものに絞り込み、さらにTitleフィールドと完全一致したものに重みを付けています。
var index = ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>();
// Contentフィールドが"Foo"を含むものに絞り込み
query = query.Filter(item => item["Content"].Contains("Foo"));
// Titleフィールドが"Foo"と一致する場合に重みをつける
// ORで連結しているので、条件全体として常に真となる。
var boostPred = PredicateBuilder
.Create<SearchResultItem>(item => item.Name.MatchWildcard("*")).Boost(0) // 常に真
.Or(item => item["Title"].Equals("Foo").Boost(10));
// 条件をクエリに適用(Filterだと重み付けを無視するためWhereを使用)
query = query.Where(boostPred);
// 重みの降順で並び替えて取得
var result = query.OrderByDescending(item => item["score"]).GetResults();
}
boostPred
で真となる条件をORで結合しています。初期値にPredicateBuilder.True<SearchResultItem>()
を使用すると、クエリ生成時に条件が無視されてしまい、期待した動作になりません。
またフィルター処理と重み付けを同時に行うこともできますが、多くの場合条件を分けることで柔軟で効率の良いクエリを作成することができます。
OR/AND条件を動的生成する
リストの値それぞれに対して条件をかけたい場合、AND/OR条件を動的生成する必要があります。
以下の例では、values
変数の全ての値がアイテムのTitleフィールドに含まれている条件を生成しています。
var values = new [] { "Foo", "Bar", "Baz" };
var index = ContentSearchManager.GetIndex("sitecore_master_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>();
// true && item["Title"].Contains(value1) && item["Title"].Contains(value2) && ...
// という条件を動的生成
var pred = PredicateBuilder.Create<SearchResultItem>(item => item.Name.MatchWildcard("*"));
foreach (var value in values)
{
pred = pred.And(item => item["Title"].Contains(value));
}
// 条件をクエリに適用
query = query.Filter(pred);
var result = query.GetResults();
}
pred
の初期値として、常に真になる条件を与えています。代わりにPredicateBuilder.True<SearchResultItem>()
を使用しても動作しますが、values
変数が空の場合に例外が発生してしまいます。
Posted on February 18, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.