@提炼'步骤'
关于执行这些步骤,我会采用一些“增强”的解决方案,将你的一些步骤缝合在一起。
不确定是否完整的lexer 更好,如果您完美地设计它以满足您的需求,例如仅在 hX 等中查找文本。但是您必须指的是 _serious 业务,因为实施起来可能会令人头疼。虽然我会指出我的观点并说另一种语言的Flex / Bison 解决方案(PHP 提供的支持很差,因为它是一种高级语言)将是一个“疯狂”的速度提升。
但是,幸运的是 libxml 提供了出色的功能,如下所示,您最终将拥有多个步骤。在分析内容之前,设置语言(停用词),缩小 NodeList 集并从那里开始工作。
- 加载整页
- 检测语言
- 仅将
<body> 提取到单独的字段中
- 从
<head> 和其他类似的地方释放一点内存,例如。 unset($fullpage);
- 启动你的算法(如果 pcntl - linux 主机 - 可用,分叉和发布浏览器是一个不错的功能)
在使用 DOM 解析器时,应该意识到设置可能会引入对属性 href 和 src 的进一步验证,具体取决于库(例如 parse_url 和 likes)
另一种解决超时/内存消耗问题的方法是调用 php-cli(也适用于 Windows 主机)并“继续工作”并开始下一个文档。请参阅this question 了解更多信息。
如果您向下滚动一点,请查看建议的架构 - 初始抓取只会将主体放入数据库中(在您的情况下另外还有 lang),然后运行 cron 脚本,填写 ft_index 同时使用以下函数
function analyse() {
ob_start(); // dont care about warnings, clean ob contents after parse
$doc->loadHTML("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/></head><body><pre>" . $this->html_entity_decode("UTF-8") . "</pre></body>");
ob_end_clean();
$weighted_ft = array('0'=>"",'5'=>"",'15'=>"");
$includes = $doc->getElementsByTagName('h1');
// relevance wieght 0
foreach ($includes as $h) {
$text = $h->textContent;
// check/filter stopwords and uniqueness
// do so with other weights as well, basically narrow it down before counting
$weighted_ft['0'] .= " " . $text;
}
// relevance wieght 5
$includes = $doc->getElementsByTagName('h2');
foreach ($includes as $h) {
$weighted_ft['5'] .= " " . $h->textContent;
}
// relevance wieght 15
$includes = $doc->getElementsByTagName('p');
foreach ($includes as $p) {
$weighted_ft['15'] .= " " . $p->textContent;
}
// pseudo; start counting frequencies and stuff
// foreach weighted_ft sz do
// foreach word in sz do
// freqency / prominence
}
function html_entity_decode($toEncoding) {
$encoding = mb_detect_encoding($this->body, "ASCII,JIS,UTF-8,ISO-8859-1,ISO-8859-15,EUC-JP,SJIS");
$body = mb_convert_encoding($this->body, $toEncoding, ($encoding != "" ? $encoding : "auto"));
return html_entity_decode($body, ENT_QUOTES, $toEncoding);
}
上面是一个类,类似于您的数据库,其中预先加载了页面“body”字段。
再一次,就数据库处理而言,我最终将上述解析结果插入到 全文标记的表格列 中,这样以后的查找就可以顺利进行。这是数据库引擎的巨大优势。
全文索引注意事项:
在处理少量文档时,全文搜索引擎可以在每次查询时直接扫描文档的内容,这种策略称为串行扫描。这是一些基本工具(例如 grep)在搜索时所做的事情。
你的索引算法过滤掉了一些词,好的。但是这些是通过它们承载的权重来枚举的——这里有一个策略需要考虑,因为全文字符串不会继承给定的权重。这就是为什么在示例中,给出了将字符串拆分为 3 个不同字符串的基本策略。
一旦放入数据库,列应该与此类似,因此架构可能是这样的,我们将在其中维护权重 - 并且仍然提供超快速查询方法
CREATE TABLE IF NOT EXISTS `oo_pages` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`body` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'PageBody entity encoded html',
`title` varchar(31) COLLATE utf8_danish_ci NOT NULL,
`ft_index5` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted highest',
`ft_index10` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted medium',
`ft_index15` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted lesser',
`ft_lastmodified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'last cron run',
PRIMARY KEY (`id`),
UNIQUE KEY `alias` (`alias`),
FULLTEXT KEY `ft_index5` (`ft_index5`),
FULLTEXT KEY `ft_index10` (`ft_index10`),
FULLTEXT KEY `ft_index15` (`ft_index15`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;
可以像这样添加索引:
ALTER TABLE `oo_pages` ADD FULLTEXT (
`named_column`
)
检测语言然后从那时起选择您的停用词数据库的功能是我自己遗漏的一个功能,但它很漂亮 - 并且从书上讲!所以感谢你的努力和这个答案:)
另外,请记住不仅有标题标签,还有锚/img 标题属性。如果由于某种原因您的分析进入 类似蜘蛛的状态,我建议将参考链接 (<a>) title 和 textContent 结合起来与目标页面<title>