本文只是一个山寨试验品,思路仅供参考.
--------------------------------------------------------------------------------
原理介绍:
索引建立
目录结构划分方案也只是很简易的实现了一下,通过unicode把任意连续的两个字符(中文或英文)分为4个字节来做四层目录,把索引的内容对应的主关键字(主要为了使用sql索引和唯一性)作为文件名,两个字符在索引内容中的位置作为文件后缀来存储.文件本身为0字节,不保存任何信息.
比如一条数据 "pk001","山寨索引"
山寨索引 四个字的unicode为
[0]: 113
[1]: 92
[2]: 232
[3]: 91
[4]: 34
[5]: 125
[6]: 21
[7]: 95
那么对应的文件结构为
../113/92/232/91/pk001 .0
../232/91/34/125/pk001 .1
../34/125/21/95/pk001 .2
索引使用
比如搜索"寨索引 "
则搜索 "../232/91/34/125/" 目录下的所有文件,然后根据 pk001 .1的文件后缀名1,去看 ../34/125/21/95/pk001.2文件是否存在.依次类推,最后返回一个结果集.
--------------------------------------------------------------------------------
实用性
具体的实用性还有待验证.这只是实现了精确的like搜索,而不能做常见搜索引擎的分词效果.另外海量数据重建索引的性能也是面临很严峻的问题,比如cpu负载和磁盘io负载.关于windows一个目录下可以保持多少个文件而不会对文件搜索造成大的性能损失也有待评估,不过这个可以考虑根据主键的文件名hash来增加文件目录深度降低单一目录下的文件数量.
--------------------------------------------------------------------------------
演示效果
实现了针对test标的name和caption两个字段作索引搜索.
-- 设置和获取索引文件根目录
--select dbo.xfn_SetMyIndexFileRoot('d:/MyIndex')
--select dbo.xfn_GetMyIndexFileRoot()
-- 建立测试环境
go
create table test( id uniqueidentifier , name nvarchar ( 100), caption nvarchar ( 100))
insert into test select top 3 newid (), ' 我的索引 ' , ' 测试 ' from sysobjects
insert into test select top 3 newid (), ' 我的测试 ' , ' 索引 ' from sysobjects
insert into test select top 3 newid (), ' 测试索引 ' , ' 测试索引 ' from sysobjects
insert into test select top 3 newid (), ' 我的索引 ' , ' 索引 ' from sysobjects
create index i_testid on test( id)
-- 建立索引文件
declare @t int
select @t=
dbo. xfn_SetKeyForMyIndex( id, 'testIndex' , name + ' ' + caption)
from test
-- 查询数据
select a.* from test a, dbo. xfn_GetKeyFromMyIndex( '测试 索引 我的' , 'testIndex' ) b
where a. id= b. pk
/*
0C4634EA-DF94-419A-A8E5-793BD5F54EED 我的索引 测试
2DD87B38-CD3F-4F14-BB4A-00678463898F 我的索引 测试
8C67A6C3-753F-474C-97BA-CE85A2455E3E 我的索引 测试
C9706BF1-FB1F-42FB-8A48-69EC37EAD3E5 我的测试 索引
8BBF25CC-9DBB-4FCB-B2EB-D318E587DD5F 我的测试 索引
8B45322D-8E46-4691-961A-CD0078F1FA0A 我的测试 索引
*/
--drop table test
--------------------------------------------------------------------------------
clr代码如下:编译为MyFullIndex.dll
复制代码 代码如下:
using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Collections.Generic;
public partial class UserDefinedFunctions
{
/// <summary>
/// 设置索引目录
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction ]
public static SqlBoolean SetRoot(SqlString value)
{
if (value.IsNull) return false ;
if (System.IO.Directory .Exists(value.Value))
{
root = value.Value;
return true ;
}
else
{
return false ;
}
}
/// <summary>
/// 获取索引目录
/// </summary>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction ]
public static SqlString GetRoot()
{
return new SqlString (root);
}
/// <summary>
/// 建立索引
/// </summary>
/// <param name="key"> 主键 </param>
/// <param name="indexName"> 索引名称 </param>
/// <param name="content"> 索引内容 </param>
/// <returns></returns>
[Microsoft.SqlServer.Server.SqlFunction ]
public static SqlInt32 SetIndex(SqlString key,SqlString indexName,SqlString content)
{
if (key.IsNull || content.IsNull||indexName.IsNull) return 0;
return _setIndex(key.Value,indexName.Value, content.Value);
}
/// <summary>
/// 查询索引
/// </summary>
/// <param name="word"> 关键字(空格区分) </param>
/// <param name="indexName"> 索引名称 </param>
/// <returns></returns>
[SqlFunction (TableDefinition = "pk nvarchar(900)" , Name = "GetIndex" , FillRowMethodName = "FillRow" )]
public static IEnumerable GetIndex(SqlString word,SqlString indexName)
{
System.Collections.Generic.List <string > ret = new List <string >();
if (word.IsNull || indexName.IsNull) return ret;
return _getIndex2(word.Value, indexName.Value);
}
public static void FillRow(Object obj, out SqlString pk)
{
string key = obj.ToString();
pk = key;
}
static string root = @"d:/index" ;
/// <summary>
/// 获取有空格分隔的索引信息
/// </summary>
/// <param name="word"></param>
/// <param name="indexName"></param>
/// <returns></returns>
static System.Collections.Generic.List <string > _getIndex2(string word, string indexName)
{
string [] arrWord = word.Split(new char [] { ' ' }, StringSplitOptions .RemoveEmptyEntries);
System.Collections.Generic.List <string > key_0 = _getIndex(arrWord[0], indexName);
if (arrWord.Length == 0) return key_0;
System.Collections.Generic.List <string > [] key_list=new List <string >[arrWord.Length-1];
for (int i = 0; i < arrWord.Length-1; i++)
{
System.Collections.Generic.List <string > key_i = _getIndex(arrWord[i+1],indexName);
key_list[i] = key_i;
}
for (int i=key_0.Count-1;i>=0;i--)
{
foreach (System.Collections.Generic.List <string > key_i in key_list)
{
if (key_i.Contains(key_0[i]) == false )
{
key_0.RemoveAt(i);
continue ;
}
}
}
return key_0;
}
/// <summary>
/// 获取单个词的索引信息
/// </summary>
/// <param name="word"></param>
/// <param name="indexName"></param>
/// <returns></returns>
static System.Collections.Generic.List <string > _getIndex(string word, string indexName)
{
System.Collections.Generic.List <string > ret = new List <string >();
byte [] bWord = System.Text.Encoding .Unicode.GetBytes(word);
if (bWord.Length < 4) return ret;
string path = string .Format(@"{0}/{1}/{2}/{3}/{4}/{5}/" , root,indexName, bWord[0], bWord[1], bWord[2], bWord[3]);
if (System.IO.Directory .Exists(path) == false )
{
return ret;
}
string [] arrFiles = System.IO.Directory .GetFiles(path);
foreach (string file in arrFiles)
{
string key = System.IO.Path .GetFileNameWithoutExtension(file);
string index = System.IO.Path .GetExtension(file).TrimStart(new char [] { '.' });
int cIndex = int .Parse(index);
bool bHas = true ;
for (int i = 2; i < bWord.Length - 3; i = i + 2)
{
string nextFile = string .Format(@"{0}/{1}/{2}/{3}/{4}/{5}/{6}.{7}" ,
root, indexName, bWord[i + 0], bWord[i + 1], bWord[i + 2], bWord[i + 3], key, ++cIndex);
if (System.IO.File .Exists(nextFile) == false )
{
bHas = false ;
break ;
}
}
if (bHas == true &&ret.Contains(key)==false )
ret.Add(key);
}
return ret;
}
/// <summary>
/// 建立索引文件
/// </summary>
/// <param name="key"></param>
/// <param name="indexName"></param>
/// <param name="content"></param>
/// <returns></returns>
static int _setIndex(string key,string indexName, string content)
{
byte [] bContent = System.Text.Encoding .Unicode.GetBytes(content);
if (bContent.Length <= 4) return 0;
for (int i = 0; i < bContent.Length - 3; i = i + 2)
{
string path = string .Format(@"{0}/{1}/{2}/{3}/{4}/{5}/" , root,indexName, bContent[i + 0], bContent[i + 1], bContent[i + 2], bContent[i + 3]);
if (System.IO.Directory .Exists(path) == false )
{
System.IO.Directory .CreateDirectory(path);
}
string file = string .Format(@"{0}/{1}.{2}" , path, key, i / 2);
if (System.IO.File .Exists(file) == false )
{
System.IO.File .Create(file).Close();
}
}
return content.Length;
}
};
--------------------------------------------------------------------------------
部署的sql脚本如下
--drop function dbo.xfn_SetMyIndexFileRoot
--drop function dbo.xfn_GetMyIndexFileRoot
--drop function dbo.xfn_GetKeyFromMyIndex
--drop function dbo.xfn_SetKeyForMyIndex
--drop assembly MyFullIndex
--go
CREATE ASSEMBLY MyFullIndex FROM 'd:/SQLCLR/MyFullIndex.dll' WITH PERMISSION_SET = UnSAFE;
--
go
-- 索引搜索
CREATE FUNCTION dbo. xfn_GetKeyFromMyIndex ( @word nvarchar ( max ), @indexName nvarchar ( 900))
RETURNS table ( pk nvarchar ( 100))
AS EXTERNAL NAME MyFullIndex. UserDefinedFunctions. GetIndex
go
-- 索引建立
CREATE FUNCTION dbo. xfn_SetKeyForMyIndex ( @pk nvarchar ( 900), @indexName nvarchar ( 900), @word nvarchar ( max ))
RETURNS int
AS EXTERNAL NAME MyFullIndex. UserDefinedFunctions. SetIndex
go
-- 获取索引文件根目录
CREATE FUNCTION dbo. xfn_GetMyIndexFileRoot ()
RETURNS nvarchar ( max )
AS EXTERNAL NAME MyFullIndex. UserDefinedFunctions. GetRoot
go
-- 设置索引文件根目录(默认目录为 d:/myindex )
CREATE FUNCTION dbo. xfn_SetMyIndexFileRoot ( @FileRoot nvarchar ( max ))
RETURNS bit
AS EXTERNAL NAME MyFullIndex. UserDefinedFunctions. SetRoot
go
相关推荐:
ChatGPTO1Pro模型:开启AI新纪元,免费应用带来无尽可能,苹果上的ai写作在哪里
ChatGPT3.5需要登录使用吗?AI使用的真相!,电脑版写作ai推荐怎么关闭
AI代写文章:高效创作的新风尚
如何通过AI写文章,轻松提高写作效率与质量
AI免费工具:提升效率与创意的秘密武器
SEO观看:如何通过优化提升您的网站流量和品牌影响力,龙里网络营销推广
二创AI:打破创意壁垒,引领未来内容创作新潮流,背影教案网站建设游戏
AI上的文章属于原创吗?人工智能创作内容的归属问题
seo词库优化,搜索词条优化 ,ai点选择
SEO新站优化指南:快速提升排名的必备技巧,海珠网站推广哪家有名
SEO学费多少钱?揭秘SEO培训的投资价值与回报!,郴州网站推广多少钱一个
ChatGPT手机下载后打不开?可能是这些问题导致的,解决方法在这里!,孤城ai动画
ChatGPT:我目前无法查看或解析附件,您是否遇到过这样的困扰?,ai+燃烧
ChatGPT画布打不开?如何解决这一常见问题?,Ai怎么储存为Ai格式在桌面
SEO优化10种策略:提升网站排名的有效方法,帅气ai男头白底
SEO注意事项:助力网站流量提升的关键策略,济宁快速seo优化价格
SEO场景下的数字营销:如何通过精准优化提升网站流量,陕西融发建设集团网站
什么是seo长尾词,什么是seo长尾词的概念 ,绿茶ai换脸杨超越
seo站内链接有什么作用,seo中网站内链的作用 ,781900ai
seo需要买什么,seo需要考虑什么 ,ai做表头
SEO能够助力网站流量增长,提升品牌竞争力,Seo网站排名原理
SEO学堂:开启数字营销新时代,全面提升网站排名与流量,文山ai营销推广方案
pbootcms前端翻译插件-轻松实现网站多语言支持,拓展全球市场,st ai绘画
AI自动读文:让阅读更轻松、更高效的智能革命,寄ai空
怎么降低文章的AI生成率:打造更真实、更有价值的内容
ChatGPT怎么打不开了?解决办法,轻松恢复畅通无阻!,ai订酒店ai对话
SEO做网站点击:提升网站流量的关键策略,国内ai写作论文
SEO添加:提升网站流量与排名的必备策略,seo团队成员中国人
ChatGPT不能用了?了解这一背后的真相及解决方法,ai恐怖头像
SEO怎么优化比较好?全面提升网站排名的实用技巧,高级ai玩家
SEO引擎优化方法-让你的网站流量暴增的实战指南,ai智慧树
ChatGPT免费订阅的使用限制:其潜力与挑战,ai辅助线无法对齐画板
seo管理系统是什么,seo网站管理 ,过度圆ai
seo站长什么意思,站长工具 - seo综合查询 ,ai少女身材
seo网站编辑是做什么,seo网站编辑可在家兼职 ,ai慢直播
人工AI软件的未来:智能时代的创新驱动力
GPT-3.5可以免费使用吗?AI未来的无限可能,ai烧猪
ChatGPT无服务:如何突破限制,未来人工智能的新可能,ai绘制装饰画
AI一键生成原创文章,让创作更高效更轻松!
ChatGPT昨晚突然不能使用,背后真相令人意想不到!,edga ai
SEO教你如何快速提升网站排名,打破竞争壁垒!,本溪seo优化排名公司
ChatGPT为什么页面下拉不了?问题解析与解决方案,ai对准
优化原理:提升效率、创新突破的核心法则,印刷包装推广有哪里网站
ChatGPT中文版下载免费版:智能对话新时代,尽在,ai光波
SEO译为:网站排名背后的优化策略,会展中心网站优化
360ai问答-智能时代的全能助手,未来的智慧生活,ai生成白底
目前最火的AI软件有哪些?深度解析必备工具
SEO优化知识全解析:提升网站排名的秘密武器,ai出错合集
《*采集站:带你领略全球最全*资源的宝藏平台》,seo优化易下拉瞧瞧
GoogleSEO打满分自然流量会高吗?揭开SEO优化的真相,猪插画ai