@@ -406,32 +406,50 @@ Redis自带的PUB/SUB机制,即发布-订阅模式。这种模式生产者(pro
406406## 控制拿数据库连接池资源
407407问题:数据库连接池就那么几个,但是有很多来拿怎么办?加个超时限制怎么加?
408408
409- ## Lucene原理
410- ### 倒排索引
411- 不是由记录来确定属性值,而是由属性值来确定记录的位置。
409+ ## 搜索引擎
412410
413- #### 构建过程
411+ ![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j10.png )
414412
415- 1 . 分词
416- 2 . Hash去重
417- 3 . 根据单词生成索引表,同时得到“词典文件”(词-> 单词ID)
418- 4 . 得到“倒排索引文件”(单词ID -> 包含文档ID的倒排列表)
413+ * 网页采集
414+ * 内容过滤
415+ * 信息存储
416+ * 信息检索与后台管理
419417
420- #### 词典文件(HashMap)
421-
422- ![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j7.jpg )
418+ ## 爬虫
419+ ### 原理
420+ 仅仅针对网页的源代码进行下载,不包含信息结构化提取
423421
424- #### 词典文件(B+树)
422+ * 下载工具:使用HttlClient下载,放入Vector,用ConcurrentHashMap做爬虫深度控制
423+ * URL解析逻辑:将网页源代码中的URL过滤出来放入集合
425424
426- #### 倒排索引文件
425+ 首先在下载队列中,需要安排一些源URL,当下载工具把网页源码下载下来之后,从中解析出能继续当成源URL的URL放入下载集合中,直到下载工具把下载集合中的内容都下载完成
427426
428- ![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j8.gif )
427+ ### 为什么用HttpClient为下载工具
428+ ** 简单易用,符合需求场景,不需要更高更强的功能**
429429
430- ## 爬虫优化
431- ### 下载工具
432430HttpURLConnection:本身的 API 不够友好,所提供的功能也有限
433431HttpClient:功能强大
434- OkHttp:是一个专注于性能和易用性的 HTTP 客户端。OkHttp 会使用连接池来复用连接以提高效率。OkHttp 提供了对 GZIP 的默认支持来降低传输内容的大小。OkHttp 也提供了对 HTTP 响应的缓存机制,可以避免不必要的网络请求。当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址。
432+ OkHttp:是一个专注于性能和易用性的 HTTP 客户端。OkHttp 会使用连接池来复用连接以提高效率。OkHttp 提供了对 GZIP 的默认支持来降低传输内容的大小。OkHttp 也提供了对 HTTP 响应的缓存机制,可以避免不必要的网络请求。当网络出现问题时,OkHttp 会自动重试一个主机的多个 IP 地址
433+
434+ ### 为什么用Vector
435+ ** 多线程爬虫要保证线程安全,还可以控制容量扩充的大小**
436+
437+ ArrayList,Vector主要区别为以下几点:
438+
439+ 1 . Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比;
440+ 2 . ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍;
441+ 3 . Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。
442+
443+ ### 为什么用ConcurrentHashMap做爬虫深度控制
444+ 因为需要保存的是一个【URL -> 深度】的键值对,在爬虫下载的过程中需要通过多个线程高频地对这个键值对集合进行操作,所以在增加元素的时候需要进行同步操作以免元素被覆盖,还需要避免多线程reset导致的循环依赖问题
445+
446+ ### URL如何解析并保存
447+ 在下载到网页源码之后,将其中的所有URL通过Jsoup或者对每行内容进行正则表达式提取出来,如果符合预设值的正则表达式就添加到下载集合中。
448+
449+ ### 多线程爬虫如何实现
450+ 使用Executors.newFixedThreadPool(),因为我爬虫线程基本固定不会需要销毁重建,并且可以控制线程最大数量,方便日后根据机器性能调整。
451+
452+ 如果问到线程池的原理,请参[ 这里] ( http://www.wangtianyi.top/blog/2018/05/08/javagao-bing-fa-wu-xian-cheng-chi/ ) 。
435453
436454### 抵抗反爬虫策略
437455#### 动态页面的加载
@@ -450,19 +468,87 @@ phantomjs + selenium + java
450468#### 验证码
451469图像识别
452470
453- ### 存储查询大量的数据
471+ ### 如何实现数据库连接池
472+
454473
455- 因为下载下来的HTML文件都是小文件,所以使用HDFS存储。我们需要两种节点,namenode节点来管理元数据,datanode节点来存储设计数据。
474+ #### 添加连接超时机制
475+
476+ ### [ 如何存储查询大量的HTML文件] ( https://www.zhihu.com/question/26504749 )
477+
478+ 因为下载下来的HTML文件都是小文件,所以使用HDFS存储需要考虑一下,但为了分布式与扩展还是使用。
479+
480+ 由于小文件会导致大量元数据的产生,那么变通的方法就是在文件中再创建文件,比如一个64MB的大文件,比如其中可以包含16384个4KB的小文件,但是这个64MB的大文件只占用了1个inode,而如果存放4KB的文件的话,就需要16384个inode了。
481+
482+ 那么如何寻址这个大文件中的小文件呢?方法就是利用一个旁路数据库来记录每个小文件在这个大文件中的起始位置和长度等信息,也就是说将传统文件系统的大部分元数据剥离了开来,拿到了单独的数据库中存放,这样通过查询外部数据库先找到小文件具体对应在哪个大文件中的从哪开始的多长,然后直接发起对这个大文件的对应地址段的读写操作即可。
483+
484+ 我们需要两种节点,namenode节点来管理元数据,datanode节点来存储数据。
456485
457486![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j6.jpg )
458487
459- ### 实现思路
488+ #### 实现思路
460489
461490* 文件被切块存储在多台服务器上
462491* HDFS提供一个统一的平台与客户端交互
463492* 每个文件都可以保存多个副本
464493
465- ### 优点
494+ #### 优点
4664951 . 每个数据的副本数量固定,直接增加一台机器就可以实现线性扩展
4674962 . 有副本让存储可靠性高
4684973 . 可以处理的吞吐量增大
498+
499+ ## 解析HTML
500+ * 抽取网页数据放入索引表中,插入待建立索引的信息,等待建立索引
501+ * 剪切源文件到配置的路径,建立百度快照
502+
503+ 所以这里涉及到MySQL的使用,建立这样的一些表:
504+
505+ * S_column:栏目表
506+ * S_index:配置索引然后创建索引产生的索引表,仅用于Lucene,对Lucene的查询是通过根据columnId来查数据库得到所在索引路径来查找,所以必须要把不同的栏目放在不同的文件夹中
507+ * S_index_column:上面两个表的多对多关联表
508+ * S_news:新闻业务表,存放新闻信息和某栏目的外键
509+ * S_user:用户表
510+ * T_index:保存仅用于Solr的索引信息,便于myfullretrieve建立Solr索引,对Solr的查询是通过用columnId来过滤得到的所有相关信息
511+
512+ ###TF-IDF
513+ #### 原理
514+ 如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
515+
516+ 一个词在本文出现次数/本文总词数
517+ (文章总数/这个词在所有文章中出现次数)取对数
518+ 相乘
519+
520+ #### 目的
521+ 去掉网页内容相同或相似的网页
522+
523+ #### 用法
524+ 用TF-IDF统计每个文章中少数重要词(排序后的前几个),用MD5算法把每个词算出一个16进制的数全部加在一起然后比较两个总数,如果相同,那么两篇文章中重要的词就相同的,去掉。
525+
526+ ## Lucene原理
527+ ### 搜索原理
528+ 词项查询(TermQuery)
529+ 布尔查询(BooleanQuery)
530+ 短语查询(PhraseQuery)
531+ 范围查询(RangeQuery)
532+ 百搭查询(WildardQuery)
533+ FuzzQuery(模糊)
534+
535+ ### 倒排索引
536+ 不是由记录来确定属性值,而是由属性值来确定记录的位置。
537+
538+ #### 构建过程
539+
540+ 1 . 分词
541+ 2 . Hash去重
542+ 3 . 根据单词生成索引表,同时得到“词典文件”(词-> 单词ID)
543+ 4 . 得到“频率、位置文件”(单词ID -> 包含文档ID的倒排列表)
544+
545+ Lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。
546+
547+ #### 词典文件(HashMap)
548+
549+ ![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j7.jpg )
550+
551+ #### 频率、位置文件
552+
553+ ![ ] ( https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j8.gif )
554+
0 commit comments