RavenDb学习(三)静态索引
在静态索引这块,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学习(三)静态索引的更多相关文章
- Mongodb学习笔记三(Mongodb索引操作及性能测试)
第三章 索引操作及性能测试 索引在大数据下的重要性就不多说了 下面测试中用到了mongodb的一个客户端工具Robomongo,大家可以在网上选择下载.官网下载地址:http://www.robomo ...
- Android JNI学习(三)——Java与Native相互调用
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- Django基础学习三_路由系统
今天主要来学习一下Django的路由系统,视频中只学了一些皮毛,但是也做下总结,主要分为静态路由.动态路由.二级路由 一.先来看下静态路由 1.需要在project中的urls文件中做配置,然后将匹配 ...
- Spring Boot 项目学习 (三) Spring Boot + Redis 搭建
0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...
- day 82 Vue学习三之vue组件
Vue学习三之vue组件 本节目录 一 什么是组件 二 v-model双向数据绑定 三 组件基础 四 父子组件传值 五 平行组件传值 六 xxx 七 xxx 八 xxx 一 什么是组件 首先给 ...
- Java入门学习路线目录索引
原创 Java入门学习路线目录索引 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/One_ ...
- Python基础学习三
Python基础学习三 1.列表与元组 len()函数:可以获取列表的元素个数. append()函数:用于在列表的最后添加元素. sort()函数:用于排序元素 insert()函数:用于在指定位置 ...
- ElasticSearch7.3学习(三十二)----logstash三大插件(input、filter、output)及其综合示例
1. Logstash输入插件 1.1 input介绍 logstash支持很多数据源,比如说file,http,jdbc,s3等等 图片上面只是一少部分.详情见网址:https://www.elas ...
- HTTP学习三:HTTPS
HTTP学习三:HTTPS 1 HTTP安全问题 HTTP1.0/1.1在网络中是明文传输的,因此会被黑客进行攻击. 1.1 窃取数据 因为HTTP1.0/1.1是明文的,黑客很容易获得用户的重要数据 ...
随机推荐
- getenv()函数
在PHP中getenv(参数)函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量,具体如下: “PHP_SELF” 当前正在执行脚本的文件名,与document root 相关 ...
- ReactNative 环境的搭建和启动(安卓版)
一.JAVA环境 下载 JDK 8.0 添加 %JAVA_HOME% 变量 添加 PATH:%JAVA_HOME%\bin 二.Android环境 下载 Android SDK 修复 SDK Mana ...
- js 什么是深拷贝问题?
一.什么是值类型? 二.什么是引用类型? 三.使用ES Next新特性带来的 Object.assign 方法 和 扩展运算符: 四.Object.assign 方法 和 扩展运算符的 “深入浅出” ...
- zTree变异篇:如何让同级树节点平铺而非垂直显示
昨天有一个zTree的使用者在实际的项目中有着这样一个特殊的需求,要求同级树节点能够水平显示,根据设定的宽度自动换行,效果图如下所示: 通过在浏览器调试模式下观察其同级节点的css为: 这个dis ...
- mongodb MongoDB 聚合 group(转)
MongoDB 聚合 MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). 基本语法为:db.col ...
- MySql(十七):MySql架构设计——高可用设计之思路及方案
前言: 数据库系统是一个应用系统的核心部分,要想系统整体可用性得到保证,数据库系统就不能出现任何问题.对于一个企业级的系统来说,数据库系统的可用性尤为重要.数据库系统一旦出现问题无法提供服务,所有系统 ...
- [svc]linux文件权限
linux中,每个文件拥有三种权限 f dir权限位最佳实战 权限 对文件的影响 对文件夹的影响 r 可读取/阅读文件的内容 可以列出目录内容,无法cd,ls -l看到文件名,属性是乱码. w 可修改 ...
- Python | 一行命令生成动态二维码
当我看到别人的二维码都做的这么炫酷的时候,我心动了! 我也想要一个能够吸引眼球的二维码,今天就带大家一起用 Python 来做一个炫酷的二维码! 首先要安装工具 myqr: pip install m ...
- Redis为什么使用单进程单线程方式
Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库,由C语言编写.官方提供的数据是可以达到100000+的qps.这个数据不比采用单进程多线程的同样基于内存的KV数据库Memcached ...
- 每日英语:Bosses May Use Social Media to Discriminate Against Job Seekers
Many companies regularly look up job applicants online as part of the hiring process. A new study su ...