使用RavenDB中的Where子句查询术语

时间:2014-06-13 14:19:30

标签: ravendb

使用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();

我们想在搜索输入字段中添加一个AutoCompletion,为此我们需要获取索引的条款(查询字段)

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

在RavenDB Studio中,可以从索引中获取存储的,已分析的术语: enter image description here

- &GT;如何在客户端代码中使用查询获取这些值?

感谢您的建议

2 个答案:

答案 0 :(得分:0)

你可以查询这样的索引:

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

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

Title, Description, Article    

答案 1 :(得分:0)

没有其他方法可以获得索引的条款。要获得术语,客户端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();
            }
        }
    }
}

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