レイヴンは、その表現でそれをサポートしているようには見えません. 興味深いことに、クエリx => queryTerm.StartsWith(x.Url)
は次の行に沿って何かに分解できます。
x => x.Url == queryTerm ||
x.Url == queryTerm.Remove(queryTerm.Length - 1) ||
x.Url == queryTerm.Remove(queryTerm.Length - 2) ||
x.Url == queryTerm.Remove(queryTerm.Length - 3) ||
x.Url == queryTerm.Remove(queryTerm.Length - 4) ||
etc.
次のように体系化できます。
var terms = Enumerable.Range(0, queryTerm.Length)
.Skip(1)
.Select(i => queryTerm.Remove(i));
pages = session.Query<MyDocument>()
.Where(x => terms.Contains(x.Url));
ただし、レイヴンもそのようにはサポートしていませんContains()
。だから私はこれをコード化しました:
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Linq;
namespace RavenTest
{
[TestFixture]
public class HowToDoBackwardsStartsWithInRaven
{
private readonly string[] _testUrls = new[]
{
"www.bad.com",
"www.test.com",
"www.test.com/abc",
"www.test.com/abc/xyz"
};
private readonly string _queryTerm = "www.test.com/abc";
private readonly string[] _expectedResults = new[]
{
"www.test.com",
"www.test.com/abc"
};
[Test]
public void FailsWithContains()
{
List<MyDocument> results;
using (var store = InitStore())
{
LoadTestData(store);
using (var session = store.OpenSession())
{
var terms = GetAllStartingSubstrings(_queryTerm);
results = session.Query<MyDocument>()
.Where(x => terms.Contains(x.Url))
.ToList();
}
}
Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
}
[Test]
public void SucceedsWithSuperWhere()
{
List<MyDocument> results;
using (var store = InitStore())
{
LoadTestData(store);
using (var session = store.OpenSession())
{
var terms = GetAllStartingSubstrings(_queryTerm);
var query = session.Query<MyDocument>()
.Where(x => x.Url.Length <= _queryTerm.Length);
foreach (var term in terms)
query = query.Where(x => x.Url == term ||
x.Url.Length != term.Length);
results = query.ToList();
}
}
Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
}
private static IDocumentStore InitStore()
{
var store = new EmbeddableDocumentStore
{
RunInMemory = true,
};
return store.Initialize();
}
private static string[] GetAllStartingSubstrings(string queryTerm)
{
return Enumerable.Range(0, queryTerm.Length)
.Skip(1)
.Select(i => queryTerm.Remove(i))
.ToArray();
}
private void LoadTestData(IDocumentStore store)
{
using (var session = store.OpenSession())
{
foreach (var testUrl in _testUrls)
session.Store(new MyDocument {Url = testUrl});
session.SaveChanges();
}
}
public class MyDocument
{
public string Id { get; set; }
public string Url { get; set; }
}
}
}
さて...インデックス作成がどれほど効率的かはわかりませんが、テストは成功します。