【问题标题】:Querying for terms with a Where clause in RavenDB在 RavenDB 中使用 Where 子句查询术语
【发布时间】:2016-01-08 03:37:58
【问题描述】:

使用 RavenDB 可以获得索引的术语。此功能已记录在 here

小问题:是否有可能通过索引的其他字段过滤术语?

长问题: 我们正在创建一个知识库应用程序,我们的客户可以在其中存储主题。

我们建立了一个用于全文搜索的索引,并且我们正在索引所有主题。在索引中,我们有 2 个可查询的属性:CompanyName、Query

public class SearchQueryResult
{
    public string Query { get; set; }

    public string CompanyName { get; set; }
}

public class FullTextIndex : AbstractIndexCreationTask<Topic, SearchQueryResult>
{
    public FullTextIndex()
    {
        Map = topics => from topic in topics
            from content in topic.Content
            select new
            {
                topic.CompanyName,
                Query = new object[]
                {
                    content.Title,
                    content.Description,
                    content.Article            
                }
            };

        Analyzers.Add(x => x.Query, typeof(OurCustomHtmlStandardAnalyzer).AssemblyQualifiedName);

        Indexes.Add(x => x.Query, FieldIndexing.Analyzed);
        Stores.Add(x => x.Query, FieldStorage.Yes);
    }
}

对于全文查询,我可以将结果限制为相应的用户公司。

var results = _documentSession.Query<SearchQueryResult, FullTextIndex>()
            .Where(x => x.Query.StartsWith(input))
            .Where(x => x.CompanyName == "MyCompany")
            .OfType<Topic>()
            .ToList();

我们想向我们的搜索输入字段添加一个自动完成功能,为此我们需要获取索引的术语(查询字段)

问题是,索引确实包含所有公司的条款,而我们只需要当前公司的条款。

在 RavenDB Studio 中,可以从索引中获取存储、分析的术语:

--> 如何在我的客户端代码中通过查询获得这些值?

感谢您的建议

【问题讨论】:

    标签: ravendb


    【解决方案1】:

    没有其他方法可以获取索引的术语。要获取条款,客户端 api 提供的唯一功能记录在 here

    因此,如果您必须通过某些属性值过滤术语,则必须将 where 子句移至索引定义。

    如果预先知道要过滤的值,则可以使用继承自AbstractIndexCreationTask的静态索引定义类

    public class FullTextIndex : AbstractIndexCreationTask<Topic, SearchQueryResult>
    {
        public FullTextIndex()
        {
            Map = topics => from topic in topics
                where topic.CompanyName == "TheFirm"
                from content in topic.Content
                select new
                {
                    topic.CompanyName,
                    Query = new object[]
                    {
                        content.Title,
                        content.Description,
                        content.Article            
                    }
                };
    
            Analyzers.Add(x => x.Query, typeof(OurCustomHtmlStandardAnalyzer).AssemblyQualifiedName);
    
            Indexes.Add(x => x.Query, FieldIndexing.Analyzed);
            Stores.Add(x => x.Query, FieldStorage.Yes);
        }
    }
    

    注意 Map 部分中的 where 子句。

    如果您事先不知道过滤值,例如如果您有多家公司,您可以为每家公司建立一个专门的索引。所以你最终会得到一些静态索引,如 FullTextIndexForXXXX、FullTextIndexForYYYY 等。

    然后,此索引包含过滤,您可以使用 RavenDB Client api 提供的 GetTerms 函数来获取术语。

    我必须动态构建索引定义。
    我正在使用 IndexFactory 创建索引。 (必须在应用程序启动时调用)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Raven.Abstractions.Indexing;
    using Raven.Client;
    
    namespace MyNamespace.Data.Index.FullTextIndex
    {
        public static class FullTextIndexFactory
        {
            public static void CreateFullTextIndexes(IDocumentStore documentStore)
            {
                try
                {
                    var companies = GetCompanies(documentStore);
    
                    foreach (var company in companies)
                    {                   
                        var indexName = "FullTextIndexFor" + company.Name;
    
                        var indexDefinition = CreateIndexDefinition(documentStore, company);
                        var existingIndexDefinition = documentStore.DatabaseCommands.GetIndex(indexName);
                        if (existingIndexDefinition == null)
                        {
                            CreateIndex(documentStore, indexDefinition, indexName);
                            continue;
                        }
    
                        if (existingIndexDefinition.Equals(indexDefinition))
                            continue;
    
                        UpdateIndex(documentStore, indexDefinition, indexName);                
                    }
                }
                catch (Exception exception)
                {
                    // do something with the exception
                }
            }
    
            public static void CreateIndex(IDocumentStore documentStore, IndexDefinition indexDefinition, string indexName)
            {
                documentStore.DatabaseCommands.PutIndex(indexName, indexDefinition);
            }
    
            public static void UpdateIndex(IDocumentStore documentStore, IndexDefinition indexDefinition, string indexName)
            {
                documentStore.DatabaseCommands.DeleteIndex(indexName);
                CreateIndex(documentStore, indexDefinition, indexName);
            }
    
            public static IndexDefinition CreateIndexDefinition(IDocumentStore documentStore, Company company)
            {
                var indexDefinition = new IndexDefinition();
    
                var mapBuilder = new StringBuilder();
                mapBuilder.AppendLine("docs.Topics.SelectMany(topic => topic.Content, (topic, content) => new");
                mapBuilder.AppendLine("{");
                mapBuilder.AppendLine("    topic = topic,");
                mapBuilder.AppendLine("    content = content");
                mapBuilder.AppendLine("})");
                mapBuilder.AppendFormat(".Where(this0 => this0.topic.CompanyName == \"{0}\")", company.Name);
                mapBuilder.AppendLine(".Select(this0 => new ");
                mapBuilder.AppendLine("{");
                mapBuilder.AppendLine("    CompanyName = this0.topic.CompanyName,");
                mapBuilder.AppendLine("    Query = new object[]");
                mapBuilder.AppendLine("    {");
                mapBuilder.AppendLine("       this0.content.Value.Title,");
                mapBuilder.AppendLine("       this0.content.Value.Description,");
                mapBuilder.AppendLine("       this0.content.Value.Article");
                mapBuilder.AppendLine("    },");
                mapBuilder.AppendLine("    PublishStartDate = this0.topic.PublishStartDate,");
                mapBuilder.AppendLine("    PublishEndDate = this0.topic.PublishEndDate,");
                mapBuilder.AppendLine("})");
    
                var map = mapBuilder.ToString();
                indexDefinition.Maps.Add(map);
    
                indexDefinition.Name = "FullTextIndexFor" + company.Name;
    
                var analyzerAssemblyQualifiedName = typeof(CustomFullTextAnalyzer).AssemblyQualifiedName;
                indexDefinition.Analyzers.Add("Query", analyzerAssemblyQualifiedName);
    
                indexDefinition.Stores.Add("Query", FieldStorage.Yes);
    
                return indexDefinition;
            }
    
            private static IEnumerable<Company> GetCompanies(IDocumentStore documentStore)
            {
                using (var session = documentStore.OpenSession())
                {
                    return session.Query<Company>().ToList();
                }
            }
        }
    }
    

    希望如果有人有类似要求,这会有所帮助。

    【讨论】:

      【解决方案2】:

      你可以像这样查询索引:

      var results = _documentSession.Query<SearchQueryResult, FullTextIndex>()            
                  .Where(x => x.CompanyName == "MyCompany")
                  .Select(x=>x.Query)
                  .ToList();
      

      然后在结果上使用 foreach 循环,这将显示您的查询属性

      Title, Description, Article    
      

      【讨论】:

      • 感谢您的回答!如果我想要文章中的所有单词,那将起作用。但是我们有一个自定义分析器,可以去除文章中的所有 html 标记和停用词。
      猜你喜欢
      • 1970-01-01
      • 2013-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多