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

简介: 接下去我们进行索引建立,本项目索引建立我们使用Lucene.Net。在使用前我们介绍以下Lucene是什么!Lucene概述Lucene是一款高性能的、可扩展的信息检索(IR)工具库。

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

Lucene概述

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

索引过程:

①获取内容

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

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

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

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

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

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


img_d2b12d7465e79b9660ae26137412bdd8.png
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}");
            }
        }
目录
相关文章
|
存储 缓存 Oracle
|
2月前
|
XML JSON API
Json实现根据关键词搜索请求唯品会商品列表数据方法,唯品会商品列表数据接口,唯品会API接口申请指南,支持全站
Json实现根据关键词搜索请求唯品会商品列表数据方法,唯品会商品列表数据接口,唯品会API接口申请指南,支持全站
143 1
|
数据采集 分布式计算 关系型数据库
离线计算-国内查询转换率|学习笔记
快速学习离线计算-国内查询转换率
165 0
|
SQL 运维 数据可视化
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(4)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(4)
158 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(4)
|
缓存 架构师 容灾
50份架构文档荟萃(分布式事务-缓存-消息-搜索、电商、支付,多活...)
50份架构文档荟萃(分布式事务-缓存-消息-搜索、电商、支付,多活...)
192 0
|
设计模式 监控 搜索推荐
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(2)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(2)
291 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(2)
|
SQL 缓存 监控
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(6)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(6)
363 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(6)
|
运维 监控 数据可视化
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(5)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(5)
199 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(5)
|
设计模式 数据可视化 测试技术
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(3)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(3)
164 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(3)
|
数据可视化 安全 容灾
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(1)
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(1)
154 0
【技术干货】40页PPT分享万亿级交易量下的支付平台设计(1)