在静态索引这块,RavenDb其实的是lucene,所以里面有很多概念,其实都是lucene本身的。

.定义静态Indexes
documentStore.DatabaseCommands.PutIndex(
    "BlogPosts/PostsCountByTag",
    new IndexDefinitionBuilder<BlogPost, BlogTagPostsCount>
    {
        // The Map function: for each tag of each post, create a new BlogTagPostsCount
        // object with the name of a tag and a count of one.
        Map = posts => from post in posts
                       from tag in post.Tags
                       select new
                       {
                           Tag = tag,
                           Count =
                       },

        // The Reduce function: group all the BlogTagPostsCount objects we got back
        // from the Map function, use the Tag name as the key, and sum up all the
        // counts. Since the Map function gives each tag a Count of 1, when the Reduce
        // function returns we are going to have the correct Count of posts filed under
        // each tag.
        Reduce = results => from result in results
                            group result by result.Tag
                                into g
                                select new
                                {
                                    Tag = g.Key,
                                    Count = g.Sum(x => x.Count)
                                }
    });
public class BlogTagPostsCount
{
    public string Tag { get; set; }
    public int Count { get; set; }
}

.索引层次化的数据
如下图中的数据,如果我们要索引Comments的话,应该如何索引
{  //posts/123
  'Name': 'Hello Raven',
  'Comments': [
    {
      'Author': 'Ayende',
      'Text': '...',
      'Comments': [
        {
          'Author': 'Rahien',
          'Text': '...',
          "Comments": []
        }
      ]
    }
  ]
}

store.DatabaseCommands.PutIndex("SampleRecurseIndex", new IndexDefinition
{
    Map = @"from post in docs.Posts
            from comment in Recurse(post, (Func<dynamic, dynamic>)(x => x.Comments))
            select new
            {
                Author = comment.Author,
                Text = comment.Text
            }"
});

当然我们也可以定义一个类
public class SampleRecurseIndex : AbstractIndexCreationTask<Post>
{
    public SampleRecurseIndex()
    {
        Map = posts => from post in posts
                       from comment in Recurse(post, x => x.Comments)
                       select new
                       {
                           Author = comment.Author,
                           Text = comment.Text
                       };
    }
}

然后创建new SampleRecurseIndex().Execute(store);

.索引相关文档

)第一个例子

这个例子:Invoice和Customer,Invoice当中包含了Customer的Id ,现在我们要通过Customer的姓名来查询invoices
public class Invoice
{
    public string Id { get; set; }

    public string CustomerId { get; set; }
}

public class Customer
{
    public string Id { get; set; }

    public string Name { get; set; }
}

public class SampleIndex : AbstractIndexCreationTask<Invoice>
{
    public SampleIndex()
    {
        Map = invoices => from invoice in invoices
                          select new
                          {
                              CustomerId = invoice.CustomerId,
                              CustomerName = LoadDocument<Customer>(invoice.CustomerId).Name
                          };
    }
}

建立完索引之后,我们就可以客户的名称来查询invoices了 

)第二个例子
public class Book
{
    public string Id { get; set; }

    public string Name { get; set; }
}

public class Author
{
    public string Id { get; set; }

    public string Name { get; set; }

    public IList<string> BookIds { get; set; }
}

public class AnotherIndex : AbstractIndexCreationTask<Author>
{
    public AnotherIndex()
    {
        Map = authors => from author in authors
                         select new
                             {
                                 Name = author.Name,
                                 Books = author.BookIds.Select(x => LoadDocument<Book>(x).Name)
                             };
    }
}

Author当中保存了所有的书的id,通过作者可以查询他出了多少书,通过书名页可以查到作者

这里面需要注意的是:
)当相关文档变化的时候,索引也会变化
)使用LoadDocument 去跟踪一个文档,当多个文档跟踪同一个文档的时候,这会变成一个很耗费资源的开销

.TransformResults
有时候索引非常复杂,但是我们需要的数据比较简单,这个时候我们需要怎么做呢?
public class PurchaseHistoryIndex : AbstractIndexCreationTask<Order, Order>
{
    public PurchaseHistoryIndex()
    {
        Map = orders => from order in orders
                        from item in order.Items
                        select new
                        {
                            UserId = order.UserId,
                            ProductId = item.Id
                        };

        TransformResults = (database, orders) =>
                           from order in orders
                           from item in order.Items
                           let product = database.Load<Product>(item.Id)
                           where product != null
                           select new
                           {
                               ProductId = item.Id,
                               ProductName = product.Name
                           };
    }
}

我们在查询的时候只需要PurchaseHistoryViewItem,这样子我们就用OfType来进行类型转换。
documentSession.Query<Shipment, PurchaseHistoryIndex>()
    .Where(x => x.UserId == userId)
    .OfType<PurchaseHistoryViewItem>()
    .ToArray();

.错误处理
当索引出现错误的时候,因为它是由一个后台线程执行的,索引我们很难发现的,通过查看'/stats'表或者 '/raven/studio.html#/statistics'或者'/raven/statistics.html'。
当错误超过15%的时候,索引就会被禁用掉,%的数量是在前10个文档之后统计的,为了防止一开始的文旦就不好使,就别禁用了。
下面是错误的一些信息,查看'/stats'得到的
{
    "LastDocEtag": "00000000-0000-0b00-0000-000000000001",
    "LastAttachmentEtag": "00000000-0000-0000-0000-000000000000",
    ,
    ,
    ,
    "StaleIndexes": [],
    ,
    ,
    "Indexes":[
        {
            "Name": "PostsByTitle",
            ,
            ,

        }
    ],
    "Errors":[
        {
            "Index": "PostsByTitle",
            "Error": "Cannot   perform   runtime   binding   on   a   null   reference",
            "Timestamp": "\/Date(1271778107096+0300)\/",
            "Document": "bob"
        }
    ]
}

.查询

在查询当中用 string.Contains()方式是会报错的,因为RavenDb不支持类似通配符*term*这样的方式,这样会引起性能问题,它会抛出NotSupportedException异常。

)多字段索引
documentStore.DatabaseCommands.PutIndex("UsersByNameAndHobbies", new IndexDefinition
{
    Map = "from user in docs.Users select new { user.Name, user.Hobbies }",
    Indexes = { { "Name", FieldIndexing.Analyzed }, { "Hobbies", FieldIndexing.Analyzed } }
});

)多字段查询
users = session.Query<User>("UsersByNameAndHobbies")
               .Search(x => x.Name, "Adam")
               .Search(x => x.Hobbies, "sport").ToList();

)相关性加速
通过设置相关性字段,可以减少一些不相关的内容搜索
users = session.Query<User>("UsersByHobbies")
               .Search(x => x.Hobbies, )
               .Search(x => x.Hobbies, ).ToList();

也可以在索引定义时候设定
public class Users_ByName : AbstractIndexCreationTask<User>
{
    public Users_ByName()
    {
        this.Map = users => from user in users
                            select new
                                {
                                    FirstName = user.FirstName.Boost(),
                                    LastName = user.LastName
                                };
    }
}

)操作符
AND操作符
users = session.Query<User>("UsersByNameAndHobbiesAndAge")
               .Search(x => x.Hobbies, "computers")
               .Search(x => x.Name, "James")
               .Where(x => x.Age == ).ToList();

上面的这一句也可以这么写
users = session.Query<User>("UsersByNameAndHobbies")
               .Search(x => x.Name, "Adam")
               .Search(x => x.Hobbies, "sport", options: SearchOptions.And).ToList();

NOT操作符
users = session.Query<User>("UsersByName")
        .Search(x => x.Name, "James", options: SearchOptions.Not).ToList();

多操作符合作
并且不等于
users = session.Query<User>("UsersByNameAndHobbies")
        .Search(x => x.Name, "Adam")
        .Search(x => x.Hobbies, "sport", options: SearchOptions.Not | SearchOptions.And)
        .ToList();

)通配符,模糊查询
EscapeAll (default),
AllowPostfixWildcard,
AllowAllWildcards,
RawQuery.
users = session.Query<User>("UsersByName")
    .Search(x => x.Name, "Jo* Ad*",
            escapeQueryOptions:EscapeQueryOptions.AllowPostfixWildcard).ToList();

users = session.Query<User>("UsersByName")
    .Search(x => x.Name, "*oh* *da*",
            escapeQueryOptions: EscapeQueryOptions.AllowAllWildcards).ToList();

users = session.Query<User>("UsersByName")
    .Search(x => x.Name, "*J?n*",
            escapeQueryOptions: EscapeQueryOptions.RawQuery).ToList();

)高亮显示

public class SearchItem
{
    public string Id { get; set; }

    public string Text { get; set; }
}

public class ContentSearchIndex : AbstractIndexCreationTask<SearchItem>
{
    public ContentSearchIndex()
    {
        Map = (docs => from doc in docs
                       select new { doc.Text });

        Index(x => x.Text, FieldIndexing.Analyzed);
        Store(x => x.Text, FieldStorage.Yes);
        TermVector(x => x.Text, FieldTermVector.WithPositionsAndOffsets);
    }
}
//查询完毕之后进行处理
FieldHighlightings highlightings;
var results = session.Advanced.LuceneQuery<SearchItem>("ContentSearchIndex")
                 .Highlight(, , out highlightings)
                 .Search("Text", "raven")
                 .ToArray();

var builder = new StringBuilder()
    .AppendLine("<ul>");

foreach (var result in results)
{
    var fragments = highlightings.GetFragments(result.Id);
    builder.AppendLine(string.Format("<li>{0}</li>", fragments.First()));
}

var ul = builder
    .AppendLine("</ul>")
    .ToString();

//查询时候设置前后符号
FieldHighlightings highlightings;
var results = session.Advanced.LuceneQuery<SearchItem>("ContentSearchIndex")
                 .Highlight(, , out highlightings)
                 .SetHighlighterTags("**", "**")
                 .Search("Text", "raven")
                 .ToArray();

)推荐

下面是用户和基于用户名的索引
public class User
{
    public string Id { get; set; }
    public string FullName { get; set; }
}

public class Users_ByFullName : AbstractIndexCreationTask<User>
{
    public Users_ByFullName()
    {
        Map = users => from user in users
                       select new { user.FullName };

        Indexes.Add(x => x.FullName, FieldIndexing.Analyzed);
    }
}

假设数据库里面存着以下数据:
// users/1
{
    "Name": "John Smith"
}
// users/2
{
    "Name": "Jack Johnson"
}
// users/3
{
    "Name": "Robery Jones"
}
// users/4
{
    "Name": "David Jones"
}

你使用了以下的查询语句
var query = session.Query<User, Users_ByFullName>().Where(x => x.FullName == "johne");
var user = query.FirstOrDefault();

如果查询不到,可以使用推荐功能
if (user == null)
{
    SuggestionQueryResult suggestionResult = query.Suggest();

    Console.WriteLine("Did you mean?");

    foreach (var suggestion in suggestionResult.Suggestions)
    {
        Console.WriteLine("\t{0}", suggestion);
    }
}

它会给你推荐
 john
 jones
 johnson
下面是包括全部参数的查询:
session.Query<User, Users_ByFullName>()
       .Suggest(new SuggestionQuery()
                    {
                        Field = "FullName",
                        Term = "johne",
                        Accuracy = 0.4f,
                        MaxSuggestions = ,
                        Distance = StringDistanceTypes.JaroWinkler,
                        Popularity = true,
                    });
另外一种查询方式:
store.DatabaseCommands.Suggest("Users/ByFullName", new SuggestionQuery()
                                                   {
                                                       Field = "FullName",
                                                       Term = "johne"
                                                   });

多个关键词的推荐:
同时输入johne davi
SuggestionQueryResult resultsByMultipleWords = session.Query<User, Users_ByFullName>()
       .Suggest(new SuggestionQuery()
       {
           Field = "FullName",
           Term = "<<johne davi>>",
           Accuracy = 0.4f,
           MaxSuggestions = ,
           Distance = StringDistanceTypes.JaroWinkler,
           Popularity = true,
       });

Console.WriteLine("Did you mean?");

foreach (var suggestion in resultsByMultipleWords.Suggestions)
{
    Console.WriteLine("\t{0}", suggestion);
}

RavenDb学习(三)静态索引的更多相关文章

  1. Mongodb学习笔记三(Mongodb索引操作及性能测试)

    第三章 索引操作及性能测试 索引在大数据下的重要性就不多说了 下面测试中用到了mongodb的一个客户端工具Robomongo,大家可以在网上选择下载.官网下载地址:http://www.robomo ...

  2. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  3. Django基础学习三_路由系统

    今天主要来学习一下Django的路由系统,视频中只学了一些皮毛,但是也做下总结,主要分为静态路由.动态路由.二级路由 一.先来看下静态路由 1.需要在project中的urls文件中做配置,然后将匹配 ...

  4. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

  5. day 82 Vue学习三之vue组件

      Vue学习三之vue组件   本节目录 一 什么是组件 二 v-model双向数据绑定 三 组件基础 四 父子组件传值 五 平行组件传值 六 xxx 七 xxx 八 xxx 一 什么是组件 首先给 ...

  6. Java入门学习路线目录索引

    原创 Java入门学习路线目录索引 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/One_ ...

  7. Python基础学习三

    Python基础学习三 1.列表与元组 len()函数:可以获取列表的元素个数. append()函数:用于在列表的最后添加元素. sort()函数:用于排序元素 insert()函数:用于在指定位置 ...

  8. ElasticSearch7.3学习(三十二)----logstash三大插件(input、filter、output)及其综合示例

    1. Logstash输入插件 1.1 input介绍 logstash支持很多数据源,比如说file,http,jdbc,s3等等 图片上面只是一少部分.详情见网址:https://www.elas ...

  9. HTTP学习三:HTTPS

    HTTP学习三:HTTPS 1 HTTP安全问题 HTTP1.0/1.1在网络中是明文传输的,因此会被黑客进行攻击. 1.1 窃取数据 因为HTTP1.0/1.1是明文的,黑客很容易获得用户的重要数据 ...

随机推荐

  1. Google Guava中的前置条件

    前置条件:让方法调用的前置条件判断更简单. Guava在Preconditions类中提供了若干前置条件判断的实用方法,我们建议[在Eclipse中静态导入这些方法]每个方法都有三个变种: check ...

  2. logstash日志分析的配置和使用(转)

    logstash是一个数据分析软件,主要目的是分析log日志.整一套软件可以当作一个MVC模型,logstash是controller层,Elasticsearch是一个model层,kibana是v ...

  3. django form 对象is_bound属性

    问题: 如果判断一个form实例中有没有数据? bug方法: 通过form实例的is_valid()方法来验证 1.Form类的定义 class YourName(Form): your_name = ...

  4. Four Node.js Gotchas that Operations Teams Should Know about

    There is no doubt that Node.js is one of the fastest growing platforms today. It can be found at sta ...

  5. Redis复制与可扩展集群搭建【转】

    本文会讨论一下Redis的复制功能以及Redis复制机制本身的优缺点以及集群搭建问题. Redis复制流程概述 Redis的复制功能是完全建立在之前我们讨论过的基于内存快照的持久化策略基础上的,也就是 ...

  6. 增加nginx虚拟主机配置文件(conf.d)

    有时候我们按照了nginx后发现配置文件只有一个,/etc/nginx/nginx.conf 所有的配置包括虚拟目录也在此文件中配置, 这样当虚拟主机多了管理就有些不方便了, 这是需要我们把配置文件拆 ...

  7. Nginx+tomcat组合实现高并发场景的动静分离和负载均衡方案

    简介 Java服务大多是跑在tomcat里,但是众所周知tomcat的并发性能没有优势(tomcat8及以上的版本可能有所改善),所以为了更好的适应高并发的应用场景,我们可以使用tomcat+ngin ...

  8. 安装 xcode 5.1.1

    https://developer.apple.com/downloads/ 切换路径xcode 路径.然并卵,不好用 http://cms.35g.tw/coding/xcode-select-%E ...

  9. JAVA线程池任务数大小设置

    线程池究竟设成多大是要看你给线程池处理什么样的任务,任务类型不同,线程池大小的设置方式也是不同的. 任务一般可分为:CPU密集型.IO密集型.混合型,对于不同类型的任务需要分配不同大小的线程池. CP ...

  10. 每日英语:American Cities May Have Hit 'Peak Office'

    Despite some hype and a few regional exceptions, the construction of office towers and suburban offi ...