RavenDB中的子字符串搜索

jwa*_*zko 10 .net c# search substring ravendb

我有一组类型的对象 Idea

public class Idea
{
    public string Title { get; set; }
    public string Body { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想通过substring搜索这个对象.例如,当我有标题" 想法 "的对象时,我希望在输入" idea "的任何子字符串时找到它:i,id,ide,idea,d,de,dea,e,ea,a.

我正在使用RavenDB来存储数据.搜索查询看起来像这样:

var ideas = session
              .Query<IdeaByBodyOrTitle.IdeaSearchResult, IdeaByBodyOrTitle>()
              .Where(x => x.Query.Contains(query))
              .As<Idea>()
              .ToList();
Run Code Online (Sandbox Code Playgroud)

索引如下:

public class IdeaByBodyOrTitle : AbstractIndexCreationTask<Idea, IdeaByBodyOrTitle.IdeaSearchResult>
{
    public class IdeaSearchResult
    {
        public string Query;
        public Idea Idea;
    }

    public IdeaByBodyOrTitle()
    {
        Map = ideas => from idea in ideas
                       select new
                           {
                               Query = new object[] { idea.Title.SplitSubstrings().Concat(idea.Body.SplitSubstrings()).Distinct().ToArray() },
                               idea
                           };
        Indexes.Add(x => x.Query, FieldIndexing.Analyzed);
    }
}
Run Code Online (Sandbox Code Playgroud)

SplitSubstrings() 是一个扩展方法,它返回给定字符串的所有不同的子串:

static class StringExtensions
{
    public static string[] SplitSubstrings(this string s)
    {
        s = s ?? string.Empty;
        List<string> substrings = new List<string>();
        for (int i = 0; i < s.Length; i++)
        {                
            for (int j = 1; j <= s.Length - i; j++)
            {
                substrings.Add(s.Substring(i, j));
            }
        }            
        return substrings.Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用.特别是因为RavenDB没有识别SplitSubstrings()方法,因为它在我的自定义程序集中.如何使这项工作,基本上如何强制RavenDB识别这种方法?除此之外,我的方法是否适合这种搜索(通过子字符串搜索)?

编辑

基本上,我想在此搜索上构建自动完成功能,因此需要快速.

在此输入图像描述

顺便说一下:我正在使用RavenDB - Build#960

jwa*_*zko 9

您可以使用以下方法跨多个字段执行子字符串搜索:

(1)

public class IdeaByBodyOrTitle : AbstractIndexCreationTask<Idea>
{
    public IdeaByBodyOrTitle()
    {
        Map = ideas => from idea in ideas
                       select new
                           {
                               idea.Title,
                               idea.Body
                           };
    }
}
Run Code Online (Sandbox Code Playgroud)

这个网站上你可以检查:

"默认情况下,RavenDB为所有内容使用名为LowerCaseKeywordAnalyzer的自定义分析器.(...)每个字段的默认值为Stores中的FieldStorage.No和Indexes中的FieldIndexing.Default."

因此,默认情况下,如果您检查raven客户端中的索引术语,它看起来如下:

Title                    Body
------------------       -----------------
"the idea title 1"       "the idea body 1"
"the idea title 2"       "the idea body 2" 
Run Code Online (Sandbox Code Playgroud)

基于此,可以构造通配符查询:

var wildquery = string.Format("*{0}*", QueryParser.Escape(query));
Run Code Online (Sandbox Code Playgroud)

然后将其.In.Where构造一起使用(在内部使用OR运算符):

var ideas = session.Query<User, UsersByDistinctiveMarks>()
                   .Where(x => x.Title.In(wildquery) || x.Body.In(wildquery));
Run Code Online (Sandbox Code Playgroud)

(2)

或者,您可以使用纯lucene查询:

var ideas = session.Advanced.LuceneQuery<Idea, IdeaByBodyOrTitle>()
                   .Where("(Title:" + wildquery + " OR Body:" + wildquery + ")");
Run Code Online (Sandbox Code Playgroud)

(3)

您也可以使用.Search表达式,但如果要搜索多个字段,则必须以不同方式构建索引:

public class IdeaByBodyOrTitle : AbstractIndexCreationTask<Idea, IdeaByBodyOrTitle.IdeaSearchResult>
{
    public class IdeaSearchResult
    {
        public string Query;
        public Idea Idea;
    }

    public IdeaByBodyOrTitle()
    {
        Map = ideas => from idea in ideas
                       select new
                           {
                               Query = new object[] { idea.Title, idea.Body },
                               idea
                           };
    }
}

var result = session.Query<IdeaByBodyOrTitle.IdeaSearchResult, IdeaByBodyOrTitle>()
                    .Search(x => x.Query, wildquery, 
                            escapeQueryOptions: EscapeQueryOptions.AllowAllWildcards,
                            options: SearchOptions.And)
                    .As<Idea>();
Run Code Online (Sandbox Code Playgroud)

摘要:

还要记住,这*term*是相当昂贵的,尤其是领先的通配符.在这篇文章中,您可以找到更多关于它的信息.据说,领先的通配符lucene对索引进行全面扫描,因此可以大大降低查询性能.Lucene在内部存储其索引(实际上是字符串字段的术语)按字母顺序排序,并从左到右"读取".这就是为什么搜索尾随通配符的速度很快而前导通配符速度慢的原因.

所以x.Title.StartsWith("something")可以使用,但这显然不会搜索所有子串.如果您需要快速搜索,可以将要搜索的字段的"索引"选项更改为"已分析",但它不会再搜索所有子字符串.

如果子字符串查询中空格键,请检查此问题以获得可能的解决方案.有关建议,请查看http://architects.dzone.com/articles/how-do-suggestions-ravendb.