这是一个专为内容网站设计的搜索引擎,具有简化但实用的英语和俄语形态支持。它为您的内容建立索引并提供全文搜索。
数据库 | 测试 |
---|---|
MySQL 5.6 或更高版本和 MariaDB 10.2 或更高版本 | |
PostgreSQL(在版本 10...16 上测试) | |
SQLite(在3.37.2上测试) |
composer require s2/rose
索引可以存储在数据库或文件中。存储充当隐藏实现细节的抽象层。在大多数情况下,您需要数据库存储PdoStorage
。
索引和搜索都需要存储。
$ pdo = new PDO ( ' mysql:host=127.0.0.1;dbname=s2_rose_test;charset=utf8 ' , ' username ' , ' passwd ' );
$ pdo -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
use S2 Rose Storage Database PdoStorage ;
$ storage = new PdoStorage ( $ pdo , ' table_prefix_ ' );
当你想重建索引时,你可以调用PdoStorage::erase()
方法:
$ storage -> erase ();
它删除索引表(如果存在)并从头开始创建新的索引表。此方法足以升级到可能无法向后兼容现有索引的 Rose 新版本。
对于自然语言处理,Rose 使用词干分析器。词干分析器截断单词的变形部分,Rose 处理生成的词干。 Rose 没有内置词典,但包含 Porter 开发的启发式词干分析器。您可以通过实现 StemmerInterface 来集成任何其他算法。
use S2 Rose Stemmer PorterStemmerEnglish ;
use S2 Rose Stemmer PorterStemmerRussian ;
// For optimization primary language goes first (in this case Russian)
$ stemmer = new PorterStemmerRussian ( new PorterStemmerEnglish ());
Indexer
构建搜索索引。这取决于词干分析器和存储。
use S2 Rose Indexer ;
$ indexer = new Indexer ( $ storage , $ stemmer );
索引器以特殊格式接受您的数据。数据必须包装在Indexable
类中:
use S2 Rose Entity Indexable ;
// Main parameters
$ indexable = new Indexable (
' id_1 ' , // External ID - an identifier in your system
' Test page title ' , // Title
' This is the first page to be indexed. I have to make up a content. ' ,
1 // Instance ID - an optional ID of your subsystem
);
// Other optional parameters
$ indexable
-> setKeywords ( ' singlekeyword, multiple keywords ' ) // The same as Meta Keywords
-> setDescription ( ' Description can be used in snippets ' ) // The same as Meta Description
-> setDate ( new DateTime ( ' 2016-08-24 00:00:00 ' ))
-> setUrl ( ' url1 ' )
-> setRelevanceRatio ( 3.14 ) // Multiplier for important pages
;
$ indexer -> index ( $ indexable );
$ indexable = new Indexable (
' id_2 ' ,
' Test page title 2 ' ,
' This is the second page to be indexed. Let ' s compose something new. '
);
$ indexable -> setKeywords ( ' content, page ' );
$ indexer -> index ( $ indexable );
Indexable
的构造函数有 4 个参数:
您可以提供的可选参数包括:关键字、描述、日期、相关性比率和 URL。关键字的索引和搜索具有更高的相关性。该描述可用于构建片段(见下文)。为此,建议使用“关键字”和“描述”元标记的内容(如果可用)。 URL 可以是任意字符串。
Indexer::index()
方法用于添加和更新索引。如果内容不变,则该方法跳过该操作。否则,内容将被删除并再次索引。
当您从网站中删除页面时,只需调用
$ indexer -> removeById ( $ externalId , $ instanceId );
全文搜索结果可以通过Finder
类获得。 $resultSet->getItems()
返回有关内容项及其相关性的所有信息。
use S2 Rose Finder ;
use S2 Rose Entity Query ;
$ finder = new Finder ( $ storage , $ stemmer );
$ resultSet = $ finder -> find ( new Query ( ' content ' ));
foreach ( $ resultSet -> getItems () as $ item ) {
// first iteration: second iteration:
$ item -> getId (); // 'id_2' 'id_1'
$ item -> getInstanceId (); // null 1
$ item -> getTitle (); // 'Test page title 2' 'Test page title'
$ item -> getUrl (); // '' 'url1'
$ item -> getDescription (); // '' 'Description can be used in snippets'
$ item -> getDate (); // null new DateTime('2016-08-24 00:00:00')
$ item -> getRelevance (); // 4.1610856664112195 0.26907154598642522
$ item -> getSnippet (); // 'This is the second page...' 'I have to make up a <i>content</i>.'
}
修改Query
对象以使用分页:
$ query = new Query ( ' content ' );
$ query
-> setLimit ( 10 ) // 10 results per page
-> setOffset ( 20 ) // third page
;
$ resultSet = $ finder -> find ( $ query );
$ resultSet -> getTotalCount (); // Returns total amount of found items (for pagination links)
提供实例 id 以限制子系统的搜索范围:
$ resultSet = $ finder -> find (( new Query ( ' content ' ))-> setInstanceId ( 1 ));
foreach ( $ resultSet -> getItems () as $ item ) {
// first iteration only:
$ item -> getId (); // 'id_1'
$ item -> getInstanceId (); // 1
}
在搜索结果中突出显示找到的单词是一种常见的做法。您可以获得突出显示的标题:
$ resultSet = $ finder -> find ( new Query ( ' title ' ));
$ resultSet -> getItems ()[ 0 ]-> getHighlightedTitle ( $ stemmer ); // 'Test page <i>title</i>'
此方法需要词干分析器,因为它考虑了形态并突出显示了所有单词形式。默认情况下,单词以斜体突出显示。您可以通过调用$finder->setHighlightTemplate('<b>%s</b>')
更改突出显示模板。
片段是包含在搜索结果页面上显示的找到的单词的小文本片段。 Rose 处理索引内容并选择最佳匹配句子。
use S2 Rose Entity ExternalContent ;
use S2 Rose Snippet SnippetBuilder ;
$ finder -> setSnippetLineSeparator ( ' · ' ); // Set snippet line separator. Default is '... '.
$ resultSet -> getItems ()[ 0 ]-> getSnippet ();
// 'I have to make up a <i>content</i>. · I have changed the <i>content</i>.'
片段中的单词以与标题中相同的方式突出显示。
如果构建片段需要大量时间,请尝试使用分页来减少处理的片段数量。
实例有助于限制搜索范围。
例如,您可以尝试使用instance_id = 1
对博客文章建立索引,并使用instance_id = 2
对评论建立索引。然后您可以运行具有不同限制的查询:
(new Query('content'))->setInstanceId(1)
通过博客文章进行搜索,(new Query('content'))->setInstanceId(2)
通过评论进行搜索,(new Query('content'))
到处搜索。建立索引时,如果省略 instance_id 或提供instance_id === null
,则内部将使用值0
。此类内容只能匹配没有instance_id限制的查询。
Rose 专为网站和 Web 应用程序而设计。默认支持HTML格式的内容。但是,可以扩展代码以支持其他格式(例如纯文本、Markdown)。这可以通过创建自定义提取器来完成:
use S2 Rose Extractor ExtractorInterface ;
use S2 Rose Indexer ;
class CustomExtractor implements ExtractorInterface
{
// ...
// Please refer to the source code
// to figure out how to create an extractor.
}
$ indexer = new Indexer ( $ storage , $ stemmer , new CustomExtractor (), new Logger ());
PdoStorage 能够识别整个索引项目集中的相似项目。
考虑这样一个场景,您有一个博客,并且其帖子是使用 Rose 进行索引的。此特殊功能允许您为每个单独的帖子选择一组其他帖子,使访问者能够探索相关内容。
全文索引中的数据结构非常适合选择相似帖子的任务。简而言之,常规搜索需要根据搜索查询中的单词选择相关帖子,而帖子推荐则需要根据给定帖子中存在的单词选择其他帖子。
您可以通过调用以下方法来检索推荐:
$ similarItems = $ readStorage -> getSimilar ( new ExternalId ( ' id_2 ' ));
// The result contains the following data:
// $similarItems[0] = [
// 'tocWithMetadata' => new TocEntryWithMetadata(...),
// 'external_id' => 'id_1',
// 'instance_id' => '1',
// 'title' => 'Test page title',
// 'snippet' => 'This is the first page to be indexed.',
// 'snippet2' => 'I have to make up a content.',
// ],
笔记
MySQL 和 PostgreSQL 数据库支持建议。由于 SQL 支持有限,它们没有在 SQLite 中实现。