世界上已经有了这么多种子搜索引擎,为什么你还要不厌其烦的做一个新的?

可以这么说,地球上大多数的种子搜索引擎的前后端技术都比较古老,虽然古老的技术既经典又好用,但是作为一个喜欢尝鲜的人,我仍然决定使用目前最为先进的开发技术制作一个功能简明的种子搜索引擎。

采用了什么技术?

前端:在vue,angular,react三大现代开发框架中选择了vue,做出这个决定的原因也仅仅是一直以来对vue的谜之好感。有时候就是这样,缘分到了不得不从,恰巧nuxtjs在9月更新了2.0,因此毫不犹豫选择了vue。
后端:在koa,gin,springboot中权衡良久,由于很长时间没有写过java,最后选择了springboot + jdk11,用写javascript的感觉来写java,还是很不错的。从追求速度上来讲,可能使用gin或Koa要更快,但是这一点提升对于我这种实验性网站来说,意义并不是很大。
全文检索:尝试了全文检索里面的比较潮的couchbase、redissearch、elasticsearch,最后选定elasticsearch,另外两个的速度虽然远高于elasticsearch,但毕竟是内存式数据库,简单功能尚可,复杂度上去后则吃内存太多。

制作过程呢?

下面我分享下大概过程,涉及到复杂原理,请自行谷歌,我不认为我可以把复杂原理描述的很简单。

关于命名:

从手中的十来个域名选择了

btzhai.top

中国国内同名的网站有几个,但是这不是问题。

关于服务器:

几经周折,购买了一台美国服务器。配置是:E5-1620|24G|1TB|200M带宽,真正的24小时人工服务。考虑到要用cloudfare,所以不需要硬防。一月1200RMB。

在此期间尝试了很多家服务器,深感这免备案服务器这一行真的是泥沙俱下。

关于爬虫:

大约8月初终于有空来着手bt搜索引擎这件事情。

首先摆在我面前的问题就是数据来源问题,要知道所谓的dht网络,说白了就是一个节点既是服务器又是客户端,你在利用dht网络下载时会广播到网络中,别的节点就会接收到你所下载文件的唯一标识符infohash(有的地方称之为神秘代码)和metadata,这里面包括了这个文件的名称、大小、创建时间、包含文件等信息,利用这个原理,dht爬虫就可以收集dht网络中的即时热门下载。

如果仅仅依靠依靠dht爬虫去爬的话,理论上初期速度大约为40w一天,30天可以收集上千万,但是dht网络里面的节点不可能总是下载新的文件,现实情况是:大多数情况下冷门的种子几年无人问津,热门种子天天数十万人下载。可以推想,随着种子基数增加,重复的infohash会越来越多,慢慢地只会增加所谓的种子热度而不会增加基数,但是没有1000w+的种子,从门面上来讲不好看。

去哪里弄1000w种子成了当时我主要研究的问题。首先我从github上选取了几个我认为比较好用的dht爬虫进行改造,让之可以直接将数据入库到elasticsearch中,并且在infohash重复的时候自动对热度+1。

elasticsearch的mapping如下,考虑到中文分词,选用了smartcn作为分词器,当然ik也是可以的。种子内的文件列表files,本来设置为nested object,因为nested query性能不高已经取消:

{"properties": {"name": {"type": "text","analyzer": "smartcn","search_analyzer": "smartcn"},"length": {"type": "long"},"popularity": {"type": "integer"},"create_time": {"type": "date","format": "epoch_millis"},"files": {"properties": {"length": {"type": "long"},"path": {"type": "text","analyzer": "smartcn","search_analyzer": "smartcn"}}}}
}

服务器上开始24小时挂着dht爬虫。期间我也尝试过多种不同语言的开源爬虫来比较性能,甚至还找人试图购买bt种子。下面这些爬虫我都实际使用过:
https://github.com/shiyanhui/dht
https://github.com/fanpei91/p2pspider
https://github.com/fanpei91/simDHT
https://github.com/keenwon/antcolony
https://github.com/wenguonideshou/zsky
然而这些dht爬虫经试验,或多或少都有些问题,有的是只能采集infohash而不能采集metadata,有的采集速度不够,有的则随时间增加资源占用越来越大。

最终确定的是这个最优解:

https://github.com/neoql/btlet

唯一不妥是运行一段时间(大约10个小时)后就会崩溃退出,可能跟采集速度有关。而在我写这篇文章的前几天,作者称已经将此问题修复,我还没有来得及跟进更新。可以说这是我实验过采集速度最快的dht爬虫。有兴趣的同学可以去尝试、PR。

爬虫正常化运行以后,我终于发现了基数问题的解决之道,那就是skytorrent关闭后dump出来的数据库和openbay,利用这大约4000w infohash数据和bthub,每天都一定可以保证有数万新的metadata入库。

关于bthub我要说的是,api请求频率太高会被封ip,发邮件询问的结果如下。经过我的反复测试,api请求间隔设为1s也是没问题的:

关于前端:

我比较习惯于先画出简单的前端再开始写后端,前端确定清楚功能以后就可以很快写出对应的接口。bt搜索引擎目前具有以下这么几个功能就足够了:

  1. 可以搜索关键词

  2. 首页可以展现之前搜索过的排行前十的关键词

  3. 可以随机推荐一些文件

  4. 可以按照相关性、大小、创建时间、热度排序

首页启动时,为了提高速度,从后台读cache,包括收录了多少infohash、随机推荐的文件名称、搜索关键词top10等等,这些cache使用@Scheduled每天自动更新一次。

点击搜索后,跳转到结果展现页面,这里只展现elasticsearch处理过highlight之后的结果而不展现所有原始结果,每页展示10个结果。

原始结果的展现放在最后一个详细画面上。

前端承载的另一个重要问题就是seo,这也是我使用nuxtjs的原因。前端功能完成以后,我为它添加了meta描述、google analytics、百度。

sitemap的添加倒是耗废了一些时间,因为是动态网页的缘故,只能用nuxt-sitemap来动态生成。

另外用媒体查询和vh、vw做了移动适配。不敢说100%,至少可以覆盖90%的设备。

关于后端:

spring data在实现核心搜索api时遇到了问题,核心搜索如果写成json,举个例子的话,可能是下面的这个样子:

{"from": 0,"size": 10,"sort": [{"_score": "desc"}, {"length": "desc"}, {"popularity": "desc"}, {"create_time": "desc"}],"query": {"multi_match": {"query": "这里是要搜索的关键词","fields": ["name", "files.path"]}},"highlight": {"pre_tags": ["<strong>"],"post_tags": ["</strong>"],"fields": {"name": {"number_of_fragments": 1,"no_match_size": 150},"files.path": {"number_of_fragments": 3,"no_match_size": 150}}}
}

highlight返回的结果将没有办法自动和entity匹配,因为这一部分数据不在source中,spring data无法通过getSourceAsMap来获取。这里需要用到NativeSearchQueryBuilder去手动配置,如果有更好的方式,请务必赐教。java代码如下:

var searchQuery = new NativeSearchQueryBuilder().withIndices("torrent_info").withTypes("common").withQuery(QueryBuilders.multiMatchQuery(param.getKeyword(), "name", "files.path")).withHighlightFields(new HighlightBuilder.Field("name").preTags("<strong>").postTags("</strong>").noMatchSize(150).numOfFragments(1), new HighlightBuilder.Field("files.path").preTags("<strong>").postTags("</strong>").noMatchSize(150).numOfFragments(3)).withPageable(PageRequest.of(param.getPageNum(), param.getPageSize(), sort)).build();
var torrentInfoPage = elasticsearchTemplate.queryForPage(searchQuery, TorrentInfoDo.class, new SearchResultMapper() {@SuppressWarnings("unchecked")@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {if (searchResponse.getHits().getHits().length <= 0) {return null;}var chunk = new ArrayList<>();for (var searchHit : searchResponse.getHits()) {// 设置info部分var torrentInfo = new TorrentInfoDo();torrentInfo.setId(searchHit.getId());torrentInfo.setName((String) searchHit.getSourceAsMap().get("name"));torrentInfo.setLength(Long.parseLong(searchHit.getSourceAsMap().get("length").toString()));torrentInfo.setCreate_time(Long.parseLong(searchHit.getSourceAsMap().get("create_time").toString()));torrentInfo.setPopularity((Integer) searchHit.getSourceAsMap().get("popularity"));// ArrayList<Map>->Map->FileList->List<FileList>var resList = ((ArrayList<Map>) searchHit.getSourceAsMap().get("files"));var fileList = new ArrayList<FileList>();for (var map : resList) {FileList file = new FileList();file.setPath((String) map.get("path"));file.setLength(Long.parseLong(map.get("length").toString()));fileList.add(file);}torrentInfo.setFiles(fileList);// 设置highlight部分// 种子名称highlight(一般只有一个)var nameHighlight = searchHit.getHighlightFields().get("name").getFragments()[0].toString();// path highlight列表var pathHighlight = getFileListFromHighLightFields(searchHit.getHighlightFields().get("files.path").fragments(), fileList);torrentInfo.setNameHighLight(nameHighlight);torrentInfo.setPathHighlight(pathHighlight);chunk.add(torrentInfo);}if (chunk.size() > 0) {// 不设置total返回不了正确的page结果return new AggregatedPageImpl<>((List<T>) chunk, pageable, searchResponse.getHits().getTotalHits());}return null;}});

关于elasticsearch:

种子搜索不需要多高的实时性,一台服务器也不需要副本,因此,index的设置都是这样:

{"settings": {"number_of_shards": 2,"number_of_replicas": 0,"refresh_interval": "90s"}
}

jvm配置了8G内存,G1GC,另外还禁了swapping:

## IMPORTANT: JVM heap size
-Xms8g
-Xmx8g
## GC configuration
-XX:+UseG1GC
-XX:MaxGCPauseMillis=50

运行得怎么样?

由于搜索比较复杂,平均搜索时间1s左右,搜索命中上百万数据时会大于2s。

下面是cloudfare的统计:

用elasticsearch和nuxtjs搭建bt搜索引擎相关推荐

  1. 初识 ElasticSearch,一个上天下地的搜索引擎 No.158

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 我想跟大家先讲这么一个故事.在2017年,我有幸参与到Elasti ...

  2. ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台

    ELK平台介绍 在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段: 以下内容来自: http://baidu.blog.51cto.com/71938/1676798 日志主要包括系统日志. ...

  3. Centos6.5使用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中分析平台实践

    Centos6.5安装Logstash ELK stack 日志管理系统 概述: 日志主要包括系统日志.应用程序日志和安全日志.系统运维和开发人员可以通过日志了解服务器软硬件信息.检查配置过程中的错误 ...

  4. ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平

    ELK平台介绍 在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段: 以下内容来自:http://baidu.blog.51cto.com/71938/1676798 日志主要包括系统日志.应 ...

  5. elasticsearch集群搭建及springboot集成使用

    elasticsearch集群搭建及springboot集成使用 1. ES介绍 2. 原理 2.1 核心概念 2.2 索引功能 2.3 ES特性 3. 分词器(analyzer) 4. 集群搭建 4 ...

  6. docker项目-搭建个人搜索引擎SearXNG

    docker项目-搭建个人搜索引擎SearXNG SearXNG简介 SearXNG是一个免费的互联网元搜索引擎,它汇总了来自更多 超过 70 个搜索服务. 文档地址:https://docs.sea ...

  7. python es 数据库 ik_Centos7 搭建ES搜索引擎,并通过go-mysql-elasticsearch 实现数据同步...

    目录[-] Centos7 搭建ES搜索引擎,并通过go-mysql-elasticsearch 实现数据同步 导语: 随着信息量的不断增加,数据库的压力也不断增加,那么mysql 对于我们全文查找帮 ...

  8. Linux搭建BT下载服务器,linux下搭建bt服务器–xbt篇

    在windows2003下搭建bt服务器对硬件的要求较高,低配置的服务器容易死机,很是麻烦. 我们考虑用linux.据我所知,在linux下面可以作为bt tracker的软件并不是不多.现在介绍两个 ...

  9. 电商管理系统源码_Dubbo/SSM/Elasticsearch/Redis/MySQL搭建分布式电商购物商城

    关注本头条号@Java架构师技术栈分享转发文章之后私信回复[源码]即可免费获取到项目全部源码文档等! 基于SOA架构的分布式购物电商商城 后台管理系统:管理商品.订单.类目.商品规格属性.用户.权限. ...

最新文章

  1. Google用更少标签生成图像,还提出一个用于训练评估GAN的库
  2. 2020 China Collegiate Programming Contest Changchun F - Strange Memory(dsu on tree + 位运算小技巧)
  3. python装饰器原理-简单了解python装饰器原理及使用方法
  4. 即日起更新机器学习相关博客
  5. linux内存爆了会怎样,linux系统中内存爆满之后会如何?
  6. Spark笔记:复杂RDD的API的理解(下)
  7. 解决公众号的加载问题
  8. dotnet pack 打包文件版本号引起 Could not load file or assembly 问题
  9. P2480-[SDOI2010]古代猪文【中国剩余定理,Lucas定理】
  10. propertysource注解 找不到文件_电脑提示Windows找不到文件?试试这两个技巧,轻松解决!...
  11. java List的简单运用
  12. 宗成庆《文本数据挖掘》学习笔记:第二章 数据预处理和标注
  13. 电脑自动出现html文件,电脑自动弹出很多网页怎么办?
  14. selenium翻页获取京东图书名称和价格
  15. 计算机视觉(东北大学)慕课参考答案
  16. 去除IntelliJ IDEA中重复代码报灰黄色的下划波浪线
  17. C++之vector的高维数组
  18. PTN学习总结---IP基础
  19. 线程间操作无效: 从不是创建控件的线程访问它。
  20. redisHyperLogLog原理解析

热门文章

  1. 练手项目2笔记之day01
  2. 微信到底是怎么来的?
  3. 产品隐私政策与使用条款
  4. 软件设计师提纲+复习资料整理(上午题)
  5. AD软件绘制stm32最小系统电路原理图与PCB图
  6. 基于混沌的一般彩色图像加密算法的Matlab实现
  7. 【自动驾驶感知领域目前研究热点】
  8. 2022年第十三届蓝桥杯大赛软件类国赛 C/C++ 大学B组
  9. ionic:点击某个商品名称,跳转到相应的商品详情页面
  10. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》导读