在静态索引这块,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. Android Studio 环境搭建参考,jdk10javac命令提示不是内部或外部命令

    https://blog.csdn.net/qq_33658730/article/details/78547789 win10下Android Studio和SDK下载.安装和环境变量配置 http ...

  2. 如何在open xml excel 中存储自定义xml数据?

    如何在open xml excel 中存储自定义xml数据? 而且不能放在隐藏的cell单元格内,也不能放在隐藏的sheet内,要类似web网站的Application变量,但还不能是VBA和宏之类的 ...

  3. js前台取用后台传递过来的map集合方式

    在处理有些特殊需求的时候,我们需要在前台页面的js中获取后台传递过来的map集合类型的参数,并且进行调用,代码如下: 在后台我们拼装出如下的集合: Map<String,Grade> gr ...

  4. django form 对象is_bound属性

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

  5. 如何使用Git 下载GitHub的东西

    1. 先安装git 2. 注册一个github账号 3. 新建一个项目 3. 打开git 运行以下命令: cd /d/workspace (切换目录到 d盘的workspace) git init ( ...

  6. Windows Mobile入门

    转自 http://www.cnblogs.com/peterzb/archive/2009/05/12/1455256.html [准备篇]        最近安排做手机视频监控方面开发,这个对我来 ...

  7. 程序包org.junit不存在和编码GBK的不可映射字符问题解决

    maven项目在打包编译时提示: 解决办法: 将pom中junit依赖中的scope给注释掉 <dependency> <groupId>junit</groupId&g ...

  8. VS2017中建立ASP.NET MVC 4.0项目

    新的项目需要运行在WIN2003上,又不想用ASPX了,只好用回ASP.NET MVC4.0了,可是在VS2017中已经没有MVC4的模板了,网上下载的安装了也没有,只好把以前的MVC4的项目拿 出来 ...

  9. TCP/IP 三次握手,温故知新

    今天看网络编程.又又一次看了一遍三次握手.曾经只知道连接有三次握手.今天发现原来断开也有三次握手. 三次握手:指通信两方彼此交换三次信息. 三次握手是在存在数据报丢失.反复和延迟的情况下,确保通信两方 ...

  10. adb -s

    当已经有多个设备连接到主机时,可以使用-s参数进行选择. 设备为adb devices列出的内容. 除此之外,-d表示只通过USB连接,-e表示只连接仿真器.