热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

dhtcrawler2换用sphinx搜索

dhtcrawler2最开始使用mongodb自带的全文搜索引擎搜索资源。搜索一些短关键字时很容易导致erlang进程calltimeout,也就是查询时间太长。对于像avi这种关键字,搜索时间长达十几秒。搜索的资源数量200万左右。这其中大部分资源只是对root文件名进行了索引

dhtcrawler2最开始使用mongodb自带的全文搜索引擎搜索资源。搜索一些短关键字时很容易导致erlang进程call timeout,也就是查询时间太长。对于像 avi 这种关键字,搜索时间长达十几秒。搜索的资源数量200万左右。这其中大部分资源只是对root文件名进行了索引

dhtcrawler2最开始使用mongodb自带的全文搜索引擎搜索资源。搜索一些短关键字时很容易导致erlang进程call timeout,也就是查询时间太长。对于像avi这种关键字,搜索时间长达十几秒。搜索的资源数量200万左右。这其中大部分资源只是对root文件名进行了索引,即对于多文件资源而言没有索引单个文件名。索引方式有部分资源是按照字符串子串的形式,没有拆词,非常占用存储空间;有部分是使用了rmmseg(我编译了rmmseg-cpp作为erlang nif库调用 erl-rmmseg)进行了拆词,占用空间小了很多,但由于词库问题很多片里的词汇没拆出来。

很早以前我以为搜索耗时的原因是因为数据库太忙,想部署个mongodb集群出来。后来发现数据库没有任何读写的状态下,查询依然慢。终于只好放弃mongodb自带的文本搜索。于是我改用sphinx。简单起见,我直接下载了coreseek4.1(sphinx的一个支持中文拆词的包装)。

现在,已经导入了200多万的资源进sphinx,并且索引了所有文件名,索引文件达800M。对于avi关键字的搜索大概消耗0.2秒的时间。搜索试试。

以下记录下sphinx在dhtcrawler的应用

sphinx简介

sphinx包含两个主要的程序:indexer和searchd。indexer用于建立文本内容的索引,然后searchd基于这些索引提供文本搜索功能,而要使用该功能,可以遵循searchd的网络协议连接searchd这个服务来使用。

indexer可以通过多种方式来获取这些文本内容,文本内容的来源称为数据源。sphinx内置mysql这种数据源,意思是可以直接从mysql数据库中取得数据。sphinx还支持xmlpipe2这种数据源,其数据以xml格式提供给indexer。要导入mongodb数据库里的内容,可以选择使用xmlpipe2这种方式。

sphinx document

xmlpipe2数据源需要按照以下格式提交:

        this is the subject
        file content
        111

该文件包含两大部分:schemadocuments,其中schema又包含两部分:fieldattr,其中由field标识的字段就会被indexer读取并全部作为输入文本建立索引,而attr则标识查询结果需要附带的信息;documents则是由一个个sphinx:document组成,即indexer真正要处理的数据。注意其中被schema引用的属性名。

document一个很重要的属性就是它的id。这个id对应于sphinx需要唯一,查询结果也会包含此id。一般情况下,此id可以直接是数据库主键,可用于查询到详细信息。searchd搜索关键字,其实可以看作为搜索这些document,搜索出来的结果也是这些document,搜索结果中主要包含schema中指定的attr。

增量索引

数据源的数据一般是变化的,新增的数据要加入到sphinx索引文件中,才能使得searchd搜索到新录入的数据。要不断地加入新数据,可以使用增量索引机制。增量索引机制中,需要一个主索引和一个次索引(delta index)。每次新增的数据都建立为次索引,然后一段时间后再合并进主索引。这个过程主要还是使用indexer和searchd程序。实际上,searchd是一个需要一直运行的服务,而indexer则是一个建立完索引就退出的工具程序。所以,这里的增量索引机制,其中涉及到的“每隔一定时间就合并”这种工作,需要自己写程序来协调(或通过其他工具)

sphinx与mongodb

上面提到,一般sphinx document的id都是使用的数据库主键,以方便查询。但mongodb中默认情况不使用数字作为主键。dhtcrawler的资源数据库使用的是资源info-hash作为主键,这无法作为sphinx document的id。一种解决办法是,将该hash按位拆分,拆分成若干个sphinx document attr支持位数的整数。例如,info-hash是一个160位的id,如果使用32位的attr(高版本的sphinx支持64位的整数),那么可以把该info-hash按位拆分成5个attr。而sphinx document id则可以使用任意数字,只要保证不冲突就行。当获得查询结果时,取得对应的attr,组合为info-hash即可。

mongodb默认的Object id也可以按这种方式拆分。

dhtcrawler2与sphinx

dhtcrawler2中我自己写了一个导入程序。该程序从mongodb中读出数据,数据到一定量时,就输出为xmlpipe2格式的xml文件,然后建立为次索引,最后合并进主索引。过程很简单,包含两次启动外部进程的工作,这个可以通过erlang中os:cmd完成。

值得注意的是,在从mongodb中读数据时,使用skip基本是不靠谱的,skip 100万个数据需要好几分钟,为了不增加额外的索引字段,我只好在created_at字段上加索引,然后按时间段来读取资源,这一切都是为了支持程序关闭重启后,可以继续上次工作,而不是重头再来。200万的数据,已经处理了好几天了。

后头数据建立好了,需要在前台展示出来。erlang中似乎只有一个sphinx客户端库:giza。这个库有点老,写成的时候貌似还在使用sphinx0.9版本。其中查询代码包含了版本判定,已经无法在我使用的sphinx2.x版本中使用。无奈之下我只好修改了这个库的源码,幸运的是查询功能居然是正常的,意味着sphinx若干个版本了也没改动通信协议?后来,我为了取得查询的统计信息,例如消耗时间以及总结果,我再一次修改了giza的源码。新的版本可以在我的github上找到:my giza,看起来我没侵犯版本协议吧?

目前dhtcrawler的搜索,先是基于sphinx搜索出hash列表,然后再去mongodb中搜索hash对应的资源。事实上,可以为sphinx的document直接附加这些资源的描述信息,就可以避免去数据库查询。但我想,这样会增加sphinx索引文件的大小,担心会影响搜索速度。实际测试时,发现数据库查询有时候还真的很消耗时间,尽管我做了分页,以使得单页仅对数据库进行少量查询。

xml unicode

在导入xml到sphinx的索引过程中,本身我输出的内容都是unicode的,但有很多资源会导致indexer解析xml出错。出错后indexer直接停止对当前xml的处理。后来查阅资料发现是因为这些无法被indexer处理的xml内容包含unicode里的控制字符,例如 ? (U+00E4)。我的解决办法是直接过滤掉这些控制字符。unicode的控制字符参看UTF-8 encoding table and Unicode characters。在erlang中干这个事居然不复杂:

strip_invalid_unicode(<<>>) ->
    <<>>;
strip_invalid_unicode(<>) ->
    case is_valid_unicode(C) of
        true ->
            RR = strip_invalid_unicode(R),
            <>;
        false ->
            strip_invalid_unicode(R)
    end;
strip_invalid_unicode(<>) ->
    strip_invalid_unicode(R).
is_valid_unicode(C) when C <16#20 ->
    false;
is_valid_unicode(C) when C >= 16#7f, C =<16#ff ->
    false;
is_valid_unicode(_) ->
    true.

推荐阅读
  • 我这几年踩过的十个坑,每一条都是血泪教训
    “阅读本文大概需要3分钟。”一、不记录程序部署在哪里“我:他妈的,这个程序明明一直在正确产生日志,可它到底运行在哪里?怎么我 ... [详细]
  • 1.淘宝模拟登录2.天猫商品数据爬虫3.爬取淘宝我已购买的宝贝数据4.每天不同时间段通过微信发消息提醒女友5.爬取5K分辨率超清唯美壁纸6.爬取豆瓣排行榜电影数据(含GUI界面版) ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • hackingTeam是如何被黑的
    hackingTeam是如何被黑的 ... [详细]
  • 数据库进入全新时代,腾讯云发布五大数据库提前布局
    8月28日,腾讯云数据库在京正式启动战略升级,宣布未来将聚焦云原生、自治、超融合三大战略方向,以用户为中心,联接未来。并在现场面向全球用户同步发布五大战略级新品,包括数据库智能管家 ... [详细]
  • mongodb_Mongodb3.6 基操命令——help有大用
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Mongodb3.6基操命令——help有大用相关的知识,希望对你有一定的参考价值。前 ... [详细]
  • 【实战】MongoDB 分片原理概述 + 部署 MongoDB 分片群集 +【源码包】
    目录:1·MongoDB分片概述2·部署MongoDB分片群集3·MongoDB分片管理4·推荐MongoDB、MySQL基础文章5·文章总结MongoDB分片概述1)什么是分片: ... [详细]
author-avatar
最好的zixue
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有