4.1、苏宁百万级商品爬取 代码讲解 索引建立

接下去我们进行索引建立,本项目索引建立我们使用Lucene.Net。在使用前我们介绍以下Lucene是什么!

Lucene概述

Lucene是一款高性能的、可扩展的信息检索(IR)工具库。信息检索是指文档搜索、文档内信息搜索或者文档相关的元数据搜索等操作。

索引过程:

①获取内容

②建立文档
获取原始内容后,就需要对这些内容进行索引,必须首先将这些内容转换成部件(通常称为文档),以供搜索引擎使用。文档主要包括几个带值的域,比如标题、正文、摘要、作者和链接。

③文档分析
搜索引擎不能直接对文本进行索引:确切地说,必须将文本分割成一系列被称为语汇单元的独立的原子元素。每一个语汇单元大致与语言中的“单词”对应起来。

④文档索引
在索引步骤中,文档被加入到索引列表。

Lucene 的参考链接,想多了解的小伙伴可以点击
借助 Lucene.Net 构建站内搜索引擎
使用Lucene.Net实现全文检索
Lucene.Net+盘古分词器(详细介绍)

在阅读上述内容和文章链接后,相信大家对Lucene是什么有了一定的了解。那么我们再来说说分词,分词我们简单理解是这样的
“今天是个好日子”通过分词中间件,我们能够得到一个集合,集合内容为["今天","是","一个","好日子"]这样的内容,相当于把内容分解成了我们日常理解的词汇。中文分词现在有很多种
庖丁解牛,盘古分词,结巴分词,IK分词等等,大家可以通过百度对分词组件进行了解,这里也不做多的说明。

本项目选用的分词组件是 盘古分词,采用Lucene.Net建立索引
索引建立是基于当前已经存在的20张表


image.png

我们是对这些数据建立索引,那我们如何高效的建立索引,当然也是多线程啦!😄

思路说明

遍历20张表
第一步、得到每张表的个数集合 Dictionary[表名,分页总数]
我们的分页以1000作为基数,即一次取1000条数据
_commodityService.GetTableCount(i) 得到当前表格的个数 (i是商品表索引号)
PageHelper.GetPageNum(A,B) A是集合,B是个数,得到的集合是对当前表的数据每次取1000个,需要分多少页

   public static int GetPageNum(int allCount, int pageSize)
        {
            int PageNum = 0;//任务分页个数
            if (allCount % pageSize == 0)
            {
                PageNum = allCount / pageSize;
            }
            else
            {
                PageNum = allCount / pageSize + 1;
            }

            return PageNum;
        }
             //分页以1000作为基数
            //Dictionary[表名,分页总数]
            Dictionary<int, int> tableCountDictionary = new Dictionary<int, int>();
            //StaticConst.CategorySheetCount=20
            for (int i = 0; i < StaticConst.CategorySheetCount; i++)
            {
                int pageNum = PageHelper.GetPageNum(_commodityService.GetTableCount(i), StaticConst.PageGetCount); ;
                tableCountDictionary.Add(i, pageNum);
            }

第二步、得到[表索引,页码]集合

对第一步的Dic字典循环,我们又得到一个新的集合列表,列表的内容是【表索引,分页索引】的集合
集合的例子是:[{0,1},{0,2},{0,3}]
解释,第一张表第一页,第一张表第二页,第一张表第三页这样的集合

   public class TableIndexModel
    {   /// <summary>
        /// 表索引
        /// </summary>
        public int TableIndex { get; set; }
        /// <summary>
        /// 分页索引
        /// </summary>
        public int PageIndex { get; set; }
    }

            //得到[表索引,页码]集合
            List<TableIndexModel> timList = new List<TableIndexModel>();
            foreach (var tcd in tableCountDictionary)
            {
                for (int i = 1; i <= tcd.Value; i++)
                {
                    timList.Add(new TableIndexModel()
                    {
                        TableIndex = tcd.Key,
                        PageIndex = i
                    });
                }
            }

第三步、定义每一个线程需要完成的内容
根据第二步骤,我们得到了一个[表索引,页码]的集合,接下去我们开始分配每个线程要完成的任务量
如果我们集合个数是3000,我们对其3000进行分页,最好是将页数定义的多一点,这样每个集合处理的任务量少,耗时少。

执行完上述代码后我们可以得到一个List<[表索引,页码]>的集合,这个集合就是我们最终得到的集合。这个集合的好处如果大家看得懂代码,能够体会到好处,那就是任务分配均匀,每个集合要处理的任务数都是相同的,这样多线程处理的时候就不会有快慢之分。能够快速切换任务和节约执行时间。

             /*平均分配任务的业务逻辑为:
                每个线程需要处理多少任务=timList.Count 总个数 /分页数
             */
            int workPageNum = PageHelper.GetPageNum(timList.Count, threadCount);

            //得到[平均分配后的任务列表]
            List<List<TableIndexModel>> taskDataList = new List<List<TableIndexModel>>();
            for (int i = 1; i <= workPageNum; i++)
            {
                var list = timList.Skip((i - 1) * threadCount).Take(threadCount).ToList();
                taskDataList.Add(list);
            }

第四步、多线程处理
如下代码因为是部分贴图,所以可能理解起来较为困难,如果有问题的观众可以直接下载github上面的源码,自己调试看看效果,有问题也可以email给我。
代码的大概意思是,开启20个线程,20个线程处理第三步得到的集合。

  • 得到一个随机编码,这是索引存储的Lucene文件夹名称,判断编码是否存在,如果不存在加入编码list集合
  • 对当前集合建立索引
  • 将当前任务加入List<Task>集合,判断任务集合是否超出20上限,如果超出,等待集合中任务完成。这一步是用来手动限定20个线程数量的。
  • 在所有任务结束后,对当前的编码集合进行索引合并。
    在索引建立时,如果存在错误,即认定索引建立失败,结束所有的任务
               List<Task> taskList = new List<Task>();
                var threadNums = Enumerable.Range(1, StaticConst.CategorySheetCount).ToList();
                Random random = new Random();
                int index = 0, alltakCount = taskDataList.Count;
                foreach (var taskData in taskDataList)
                {
                    index++;
                    var threadCode = CommodityDAL.GetTName(random.Next(1, threadNums.Count));
                    Task task = taskFactory.StartNew(() =>
                    {
                        try
                        {
                            LuceneBulid luceneBuild = new LuceneBulid();
                            if (!PathSuffixList.Any(u => u == threadCode))
                            {
                                PathSuffixList.Add(threadCode);
                            }
                            //建立索引
                            luceneBuild.BuildIndex(taskData, threadCode, true);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"BuildIndexError\t{ex.Message}");
                            CTS.Cancel();
                        }
                    }, CTS.Token);
                    taskList.Add(task);
                    if (taskList.Count > 20)
                    {
                        taskList = taskList.Where(t => !t.IsCompleted && !t.IsCanceled && !t.IsFaulted).ToList();
                        Task.WaitAny(taskList.ToArray());
                    }
                }
                taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), MergeAllLuceneIndex));

      private void MergeAllLuceneIndex(Task[] obj)
        {
            try
            {
                ILuceneBulid builder = new LuceneBulid();
                builder.MergeAllLuceneIndex(PathSuffixList.ToArray());
                OnTaskComplate(new EventArgs());//任务完成触发事件
            }
            catch (Exception ex)
            {
                StringValueEventArgs e = new StringValueEventArgs() { Value = ex.Message };
                OnTaskError(e);//每完成一个任务触发事件
                Console.WriteLine($"MergeAllLuceneIndex\t{ex.Message}{ex}");
            }
        }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容