Ads by Lake Quincy Media

eaglet

本博专注于基于微软技术的搜索相关技术
posts - 177, comments - 3003, trackbacks - 26, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

经过2周多的努力,HubbleDotNet 的内存索引功能终于搞好了。有了内存索引,搜索不再去读硬盘,实时性大大提高了。hubble的内存索引不同于lucene 的内存索引,本文将具体介绍一下hubble 的内存索引功能。

hubbledotnet 的内存索引被设计为一个可管理的可以持久化的内存索引,它和lucene 的内存索引有很大不同。lucene 的内存索引是不能持久化的,就是如果你用lucene 的内存索引,那么一旦机器重启,索引就没有了,要持久化,要同时做内存索引和文件索引。(lucene老版本是这样的,不知道新版本是否改进了)。另外 lucene 的内存索引是不可管理的,不能动态分配内存,所有索引全部加载到内存,如果索引很大,内存消耗非常大。hubbledotnet 的内存索引在设计上考虑到这些问题,下面具体谈谈。

索引的持久化

hubbledotnet 的内存索引采用了读写分离的设计。写索引还是写入到文件中,读索引从内存中读取。这样即使机器重启,索引也不会丢失。而且由于读写分离,查询时完全不读取硬盘,查询的响应时间基本上非常确定,实时性比读取文件要提高很多。对于一些实时性要求比较高的搜索项目,由于数据修改非常频繁,并且要实时显示,在这种情况下,不可能每次增量或修改都优化索引,这样必然导致产生大量的索引碎片,如果不采用内存索引,每次搜索时就要读取大量的文件,搜索速度会受到很大影响,采用内存索引后,不管有多少文件,都是从内存读取,这个问题就得到彻底的解决。

 

内存索引类型

image

 

如上图所示,要让表具备内存索引功能,只要在 tableinfo 中设置 RamIndexType 就可以了。

内存索引有如下4种类型:

NoCache : 这种类型表示不把索引加载到内存

Full: 这种类型表示把索引全部加载到内存

Dynamic: 这种类型表示动态加载内存,这个类型要和 RamIndex Min Load Size 参数配合使用,当一次读取超过最小加载大小时,将把相应的一块内存加载到内存中,这个最小加载大小的设置是为了控制加载内存的数量,较少的文件读取对搜索速度不会产生太大的影响,如果不论读取多少都加载到内存,会导致内存增长过快。最小加载大小默认值为80KB。hubbledotnet 的倒排索引压缩率比较高,每个文档在倒排索引中只占用2-4个字节,80KB大概相当于单个单词匹配2万到4万条记录左右。由于GC的大对象堆的门槛是85KB,所以我将这个默认值设置为80KB,以避免频繁到大对象堆中分配内存。

Small: 这种类型只对大小小于8MB的索引文件加载内存,这个类型主要用于那些索引更新比较频繁,且内存又不是很充裕的项目,因为这些项目往往会产生很多小的索引文件碎片。

内存管理

内存索引有个很重要的问题就是随着索引文件的增大和搜索覆盖索引的增大,内存会逐渐增长,我们必须要有一个机制来控制这个内存的总数,不能把内存全部用光。hubbledotnet 专门做了这方面的设计。

image

 

如上图所示,HubbleDotNet 提供了三个参数

RamIndexMemoryLimited: 这个参数指定内存索引的最大占用内存数,默认为64GB。一旦内存索引占用的内存数量超过这个设置或者hubbledotnet 发现申请内存时系统的物理内存可用数量少于100MB,这时HubbleDotNet 会对内存进行整理,将不经常访问的内存清除出去以腾出足够的内存。

RamIndexAllocedMemory: 这个参数是一个只读参数,它返回当前内存索引占用的内存数量。

LastSystemAvaliableMemory:这个参数是一个只读参数,它返回上一次分配内存时系统的可用物理内存数量。

 

设置最大内存数

设置最大内存数的方法很简单,只要执行如下语句就可以,比如我们要设置内存索引最大占用内存数为2GB,我们只要执行:

sp_configure 'RamIndexMemoryLimited', 2048

image

注意:这个参数的设置不需要重启Hubble服务,执行这个语句后,参数会立即生效。如果当前占用的内存数大于设置的内存数量,系统会自动整理内存,释放出多余的内存。

适用版本

1.1.5.4 版本及其以上版本

 

返回 HubbleDotNet 技术详解

标签: Hubble.Net

Feedback

#1楼  回复 引用 查看   

2011-08-10 07:24 by 大头男      
不错啊,很给力!

#2楼  回复 引用 查看   

2011-08-10 08:27 by zsea      
给力

#3楼  回复 引用 查看   

2011-08-10 08:31 by Ray Wu      
支持加佩服

#4楼  回复 引用 查看   

2011-08-10 09:26 by 曾祥展      
前天刚好用你的做全文搜索 ,效果非常好!今天改进了内存索引,很给力!

#5楼  回复 引用 查看   

2011-08-10 09:29 by Orison      
首先恭喜老大又迈进的一大步! 但,请允许我这样一个菜鸟对您的作品做些评价:
如果说Hubble有可能比lucene强,其实就强在了几个点, 1.支持实时更新 2.完善的内存管理 3.积分的高度自定义化,
不是性能,lucene的性能已经足够了, 它的扩展性在实际应用过程中也是不错的, 只有以上这三个点,lucene做的让人比较纠结

盼望老大早日实现积分的自定义化!

#6楼  回复 引用 查看   

2011-08-10 09:40 by Fred Chen      

#7楼  回复 引用 查看   

2011-08-10 09:40 by try      
引用Orison:
首先恭喜老大又迈进的一大步! 但,请允许我这样一个菜鸟对您的作品做些评价:
如果说Hubble有可能比lucene强,其实就强在了几个点, 1.支持实时更新 2.完善的内存管理 3.积分的高度自定义化,
不是性能,lucene的性能已经足够了, 它的扩展性在实际应用过程中也是不错的, 只有以上这三个点,lucene做的让人比较纠结

盼望老大早日实现积分的自定义化!


这个只是你表面看到的功能吧。内部架构比lucene强很多啊

#8楼[楼主]  回复 引用 查看   

2011-08-10 09:58 by eaglet      
@Orison
性能的比较要比较大数据量和大并发的情况。比如一秒钟并发100次,那如果单CPU的话,每次查询时间超过10ms就会有积压。在查询单个单词100万匹配记录(匹配记录不是记录总数,记录总数大于匹配记录数)的情况下,lucene 的查询速度大概是100ms左右,而hubbledotnet 大概在20ms左右,如果并发大,这个性能优势就会体现出来。并发小时无法体现,因为一次查询20ms还是100ms,对于用户来说都感觉不出来。

#9楼  回复 引用 查看   

2011-08-10 10:48 by 东方蜘蛛      
不错,一直在关注中。

#10楼  回复 引用 查看   

2011-08-10 11:59 by 遗忘海岸      
想问下
文件索引更改后,是按什么方式来更新内存索引的呢

#11楼[楼主]  回复 引用 查看   

2011-08-10 12:05 by eaglet      
@遗忘海岸
文件索引更新后,要看选择的是哪种内存索引类型,如果是full ,则文件索引更新后,直接把更新后的索引全部加载到内存,如果是动态方式则要等到查询时才动态加载。

#12楼  回复 引用 查看   

2011-08-10 12:23 by 鸽子飞扬      
支持,给力

#13楼  回复 引用 查看   

2011-08-10 13:11 by Jeff Wong      
真的很强. 完全基于内存做搜索还需要缓存吗?

#14楼[楼主]  回复 引用 查看   

2011-08-10 13:27 by eaglet      
@Jeff Wong
内存索引相当于索引级别缓存,另外还有查询级别缓存和数据级别缓存,缓存级别越高,速度越快。就是说数据级别缓存的速度是最快的。

#15楼  回复 引用 查看   

2011-08-10 14:10 by 遗忘海岸      
谢谢
真的很不错
---------------
倒排索引结构*

倒排索引优化*

UnTokenized 索引*

关系数据库索引*

这几篇什么时候出啊

#16楼  回复 引用 查看   

2011-08-10 14:13 by iImax      
内存级别 速度是刷刷的 强烈推荐

#17楼[楼主]  回复 引用 查看   

2011-08-10 14:17 by eaglet      
引用遗忘海岸:
谢谢
真的很不错
---------------
倒排索引结构*

倒排索引优化*

UnTokenized 索引*

关系数据库索引*

这几篇什么时候出啊

最近比较忙,等过段时间,我来写。

#18楼  回复 引用 查看   

2011-08-10 20:20 by overred      
ding

#19楼  回复 引用 查看   

2011-08-11 18:23 by xwy      
学习

#20楼  回复 引用 查看   

2011-08-25 20:54 by 单摆      
HubbleDotNet在查询的时候还会使用与之关联的数据库吗
我的理解是只有在建立索引或重建索引才会,有相关的介绍文章吗,谢谢

#21楼  回复 引用 查看   

2011-08-29 13:50 by 旧事重播__、      
你好,我最近一直在研究hubble,在使用的过程中遇到一些问题和疑问,希望能得到你的帮助,下面是我的问题:
1.在你的DBAdapter里,有这样一个方法,public Core.SFQL.Parse.DocumentResultWhereDictionary GetDocumentResults(int end, string where, string orderby) 这个方法,在我给hubble做MongoDB 的接口的时候,就遇到了问题! 因本人知识有限以及你的Where参数里面都是关系型数据库的操作语句,无法根据你的Where 语句进行语义分析,然后去Mongodb里面去进行操作, 不知道有什么好的解决办法吗?
2.在我做主从表的时候,我既然已经有了从表了,但是在我执行类似这样的语句:
select top 10 * from XXtable where xxcolumn match 'XX' and minprice>3 这句的时候,它还是会先去SQLServer的主表里面去查询,然后返回查询到的ID,然后再去到Mirror表里查询。 这样,还是不能从根本上起到解放主表的作用。一样主表还是有压力的,只不过可能主表的压力你已经分解成了类似 xxID in (1,2,3,4) and minprice>3这种了。 不知道你以后会不会对这个进行优化,对这种如果有从表了,就彻底的解决主表的压力。

#22楼[楼主]  回复 引用 查看   

2011-09-01 07:31 by eaglet      
1. 那个是执行非全文查询采用的。
2. 那是因为 minprice 这个字段没有做 untokenized 索引。

#23楼  回复 引用 查看   

2011-09-17 15:37 by jiang_chao      
群主你这个版本是那版的,我的1.1版的怎么找不到RamIndexType 这个属性

#24楼[楼主]  回复 引用 查看   

2011-09-18 10:18 by eaglet      
1.1.0.0 不是最新版本,请看下面文章升级到最新版本就有了。
http://www.cnblogs.com/eaglet/archive/2010/05/05/1727964.html

#25楼  回复 引用 查看   

2011-09-22 17:07 by 倚天赵海feng      
哦原来啊,我的版本要更新组件了 刚去http://hubbledotnet.codeplex.com/SourceControl/changeset/changes/80291
看了下 老大昨天又更新了啊 感谢。

#26楼  回复 引用 查看   

2011-09-22 17:15 by 倚天赵海feng      
老大的这个文档什么时候有时间更新下 啊Manual_Chinese.doc

#27楼  回复 引用 查看   

2011-11-10 11:55 by 欢迎4000      
eaglet,你好,hubble.net 现在能支持图片,视频搜索吗?如果不能,有没有你了解的免费开源的图片,视频搜索组件呀?

#28楼[楼主]  回复 引用 查看   

2011-11-10 12:46 by eaglet      
@欢迎4000
这个视频和图片搜索首先要有爬虫来抓吧?还是你只是搜索站内的啊?

#29楼  回复 引用 查看   

2011-11-14 17:31 by 欢迎4000      
eaglet,你好,目前做的还是站内搜索,不知道Hubble.net 支持不支持相关的图片,视频搜索?

#30楼  回复 引用 查看   

2011-11-16 14:05 by xmxoxo      
顶一下楼主。 不知道最新版本在哪里下载?

#31楼  回复 引用 查看   

2011-12-14 15:57 by Terry_zeng      
修改RamIndex属性时候,出现如下错误信息,还请各位赐教。
exec SP_SetTableAttribute 'T2Ext_Properties_rlist','RamIndexMinLoadSize',80



Can't set attribute:{0}, it is only can set at create statement
在 Hubble.Core.StoredProcedure.SP_SetTableAttribute.SetValue(String tableName, String attrName, String value) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\StoredProcedure\SP_SetTableAttribute.cs:行号 257
在 Hubble.Core.StoredProcedure.SP_SetTableAttribute.Run() 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\StoredProcedure\SP_SetTableAttribute.cs:行号 285
在 Hubble.Core.SFQL.Parse.SFQLParse.ExcuteExec(TSFQLSentence sentence) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\SFQL\Parse\SFQLParse.cs:行号 156
在 Hubble.Core.SFQL.Parse.SFQLParse.ExecuteTSFQLSentence(TSFQLSentence sentence) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\SFQL\Parse\SFQLParse.cs:行号 1949
在 Hubble.Core.SFQL.Parse.SFQLParse.Query(String sql) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\SFQL\Parse\SFQLParse.cs:行号 2126
在 Hubble.Core.Service.HubbleTask.Excute(String sql) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\Service\HubbleTask.cs:行号 365
在 Hubble.Core.Service.HubbleTask.MessageReceiveEventHandler(Object sender, MessageReceiveEventArgs args) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Data\Hubble.Core\Service\HubbleTask.cs:行号 180
在 Hubble.Framework.Net.TcpServer.OnMessageReceiveEvent(MessageReceiveEventArgs args) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Framework\Hubble.Framework\Net\TcpServer.cs:行号 203
在 Hubble.Framework.Net.TcpServer.HandleClientComm(Object pcb) 位置 E:\MyProject\Hubble.Net\C#\src\Hubble.Framework\Hubble.Framework\Net\TcpServer.cs:行号 546

#32楼[楼主]  回复 引用 查看   

2011-12-15 07:03 by eaglet      
@Terry_zeng
是不是服务侧的版本太低了?你升级一下版本。语句本身好像没有问题。

#33楼  回复 引用 查看   

2011-12-15 13:44 by Terry_zeng      
@eaglet
您好,下载最新版本,版本号:hubbledotnet-83836.zip
编译后,问题依然如故,测试server同时安装企业版SQL 2005/2008,不知是否有影响?

#34楼  回复 引用 查看   

2011-12-16 14:22 by Terry_zeng      
按升级步骤,问题解决。BOSS,有点歉意,因为运行Solution中QueryAnalyzer,以为QueryAnalyzer目录下的bin文件是最新的。

#35楼  回复 引用 查看   

2011-12-23 12:54 by 欢迎4000      
eaglet,你有没有遇到这种情况,我往词库里面添加关键词,然后重新索引,但是索引的速度非常慢,或者就直接死在那儿了,过了几分钟后,我给强制关掉了,但是重建索引还是成功了,请问这是个什么问题呀?

#36楼  回复 引用 查看   

2012-01-18 13:37 by tian_di      
你好,最近一直在看你的博客,例子中全都是针对某一张表建立全文索引,然后进行查询,现在有个问题,我想用输入的关键词从十张没有关联的表中去查找所有匹配的数据,这个索引该如何建?或者有什么比较好的解决方法,谢谢!

#37楼[楼主]  回复 引用 查看   

2012-01-19 13:52 by eaglet      
@tian_di
可以用联合查询,UnionSelect
请看下面文章中关于同构表和异构表联合查询的介绍
http://www.cnblogs.com/eaglet/archive/2010/09/08/1821378.html

#38楼  回复 引用 查看   

2012-02-01 13:23 by tian_di      
你好,非常感谢!现在还有一个比较大的问题,就是这个框架能不能对本地磁盘上的海量数据(大概有几十个G,包括.doc、.xls、.pdf等)进行全文检索,并且将匹配结果和数据库中的匹配结果相互合并?或者有什么比较好的解决方案,谢谢!

#39楼[楼主]  回复 引用 查看   

2012-02-14 10:35 by eaglet      
@tian_di
如果做成被动方式的话,需要为本地文件做一个数据库驱动器。

#40楼  回复 引用 查看   

2012-02-20 10:42 by tian_di      
@eaglet
你好,你的意思是需要把本地文件以某种方式存到数据库中,然后再通过Hubble.net创建索引,从而实现全文检索?能否详细一些。

#41楼[楼主]  回复 引用 查看   

2012-02-22 13:12 by eaglet      
@tian_di
导入到数据库也是可以的。我的意思是写个特殊的数据库适配器,数据源是文件。

#42楼  回复 引用 查看   

2012-02-23 12:57 by tian_di      
@eaglet
你好,非常感谢!
不清楚自己写这样的数据库适配器的难度系数有多大,还有这样的话,搜索是否很耗时。能否提供一些思路。实在不行只好导入数据库中了。

#43楼[楼主]  回复 引用 查看   

2012-02-23 13:48 by eaglet      
@tian_di
难度系数很难评估,应该视个人的编程水平吧。对于不经常编写底层软件的人来说,可能会有一点难度。查询应该很快,如果这个适配器做得好的话。