トークン化されたクエリ文字列に基づいてフィルタリングシステムを作成し、ファームのリストを返す方法を探しています。LinqとEFでフィルタリングされたトークン化検索結果
フィルタリングメカニズムは、結果を返すためにトークンを任意の順序で供給するのに十分なほど柔軟性があることを望みます。
状態:WA作物:バナナ
は作物banana
とWA
に私のすべての農場のフィルタリングされたリストを与えるだろう、検索のための
ルールは次のようになります。
作物:バナナの状態:WA
は同じ結果を返す必要があります。
市:アルバニー作物:バナナ
は私に作物banana
とAlbany
内のすべての農場のフィルタリングされたリストを与えるだろう。
各値を引用符で囲んで、スペース区切り値をグループ化することができます。例えば
市:「マウント・バーカー」作物:バナナ
は私作物banana
とMount Barker
内のすべての農場のフィルタリングされたリストを与えるだろう。
トークン化されていないクエリでは、ファームのDetails
プロパティ内を調べるだけで、複数の単語クエリを組み合わせて引用符でファームのリストを再度返すことができます。
--------------------------------------- EDIT ------ --------------------------------------
現在の述語を使用する検索システムは、コード化されています次のように。私はこれが何らかの魂によってリファクタリングされることを望んでいるが、それは長い(申し訳ありません)、私の最初の試みです。事前に
感謝:
public ActionResult Search(string query, int? page)
{
IQueryable<Farm> farms = this.ReadOnlySession.All<Farm>();
if (!String.IsNullOrWhiteSpace(query))
{
// http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder
var predicate = PredicateBuilder.True<Farm>();
// We want to replace the spaces in quoted values here so we can split by space later.
// http://stackoverflow.com/questions/2148587/regex-quoted-string-with-escaped-quotes-in-c
Regex quoted = new Regex(@"""[^""\\]*(?:\\.[^""\\]*)*""");
foreach (var match in quoted.Matches(query))
{
query = query.Replace(match.ToString(), match.ToString().Replace(' ', '-'));
}
// Tidy up the query to remove "".
string[] splitQuery = HttpUtility.UrlDecode(query).Replace("\"", "").Split(' ');
Dictionary<string, string> tokenDictionary = new Dictionary<string, string>();
// Loop through our string[] and create a dictionary. Guids used to allow multiple keys
// of the same value.
Parallel.ForEach(splitQuery, subQuery =>
{
string[] tempArray = subQuery.Split(':');
if (tempArray.Length == 2)
{
tokenDictionary.Add(String.Format("{0}:{1}", tempArray[0], Guid.NewGuid()), tempArray[1]);
}
else
{
tokenDictionary.Add(String.Format("description:{0}", Guid.NewGuid()), subQuery);
}
});
// Loop through the dictionary and create our predicate.
foreach (KeyValuePair<string, string> item in tokenDictionary)
{
string value = item.Value.Replace('-', ' ');
string key = item.Key.Split(':')[0].ToUpperInvariant();
switch (key)
{
case "CROP":
value = Utilities.CreateSlug(value, OzFarmGuideConfig.RemoveDiacritics);
predicate = predicate.And(x => x.Crops.Any(y => value.Equals(y.Slug, StringComparison.OrdinalIgnoreCase)));
break;
case "STATE":
predicate = predicate.And(x => value.Equals(x.City.State.Name, StringComparison.OrdinalIgnoreCase));
break;
case "CITY":
value = Utilities.CreateSlug(value, OzFarmGuideConfig.RemoveDiacritics);
predicate = predicate.And(x => value.Equals(x.City.Slug, StringComparison.OrdinalIgnoreCase));
break;
default:
predicate = predicate.And(x => !String.IsNullOrWhiteSpace(x.Details) && x.Details.Contains(value));
break;
}
}
farms = farms.Where(predicate).OrderByDescending(x => x.Rating)
.ThenByDescending(x => x.RatingVotes);
PagedList<Farm> pagedFarms = new PagedList<Farm>(farms, page.HasValue ? page.Value - 1 : 0, 5);
return View(pagedFarms);
}
else
{
PagedList<Farm> pagedFarms = null;
return View(pagedFarms);
}
}
実際に私の!StringIsNullOrWhitespace呼び出しで問題を修正しましたが、コードコメントを更新するのを忘れました。私はあなたの提案をチェックしますが、よりきれいに見えます。私は今私が何か愚かなことをしているかどうかを本当に見ていると思います....ありがとう! –
ああ、 'Details'は文字列ですか?もしそうなら、私の提案は正しくないでしょう。私はそれがある種のコレクション(リスト)だと思った。 – ckittel
うん、それは....それは明らかでない場合は申し訳ありません。私はちょうど今述語で働くことに問題があります。何らかの理由で私がそれらを使うと、すべての農場が返されます。 –