Este es un motor de búsqueda diseñado para sitios de contenido con soporte de morfología en inglés y ruso simplificado pero funcional. Indexa su contenido y proporciona una búsqueda de texto completo.
Base de datos | Pruebas |
---|---|
MySQL 5.6 o posterior y MariaDB 10.2 o posterior | |
PostgreSQL (probado en las versiones 10...16) | |
SQLite (probado en 3.37.2) |
composer require s2/rose
El índice se puede almacenar en una base de datos o en un archivo. Un almacenamiento sirve como una capa de abstracción que oculta los detalles de implementación. En la mayoría de los casos necesitas almacenamiento de base de datos PdoStorage
.
El almacenamiento es necesario tanto para la indexación como para la búsqueda.
$ 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_ ' );
Cuando desee reconstruir el índice, llame al método PdoStorage::erase()
:
$ storage -> erase ();
Elimina tablas de índice (si existen) y crea otras nuevas desde cero. Este método es suficiente para actualizar a una nueva versión de Rose que puede no ser compatible con el índice existente.
Para el procesamiento del lenguaje natural, Rose utiliza lematizadores. El lematizador trunca la parte flexionada de las palabras y Rose procesa las raíces resultantes. Rose no tiene diccionarios integrados, pero incluye lematizadores heurísticos desarrollados por Porter. Puede integrar cualquier otro algoritmo implementando 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
crea el índice de búsqueda. Depende de una despalilladora y un almacenamiento.
use S2 Rose Indexer ;
$ indexer = new Indexer ( $ storage , $ stemmer );
Indexer acepta sus datos en un formato especial. Los datos deben estar incluidos en la clase 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 );
El constructor de Indexable
tiene 4 argumentos:
Los parámetros opcionales que puede proporcionar incluyen: palabras clave, descripción, fecha, índice de relevancia y URL. Las palabras clave se indexan y buscan con mayor relevancia. La descripción se puede utilizar para crear un fragmento (ver más abajo). Se sugiere utilizar el contenido de las metaetiquetas "palabra clave" y "descripción", si están disponibles, para este fin. La URL puede ser una cadena arbitraria.
El método Indexer::index()
se utiliza tanto para agregar como para actualizar el índice. Si el contenido no cambia, este método omite la operación. De lo contrario, el contenido se eliminará y se indexará nuevamente.
Cuando eliminas una página del sitio, simplemente llama
$ indexer -> removeById ( $ externalId , $ instanceId );
Los resultados de la búsqueda de texto completo se pueden obtener a través de la clase Finder
. $resultSet->getItems()
devuelve toda la información sobre los elementos de contenido y su relevancia.
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>.'
}
Modifique el objeto Query
para usar una paginación:
$ 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)
Proporcione una identificación de instancia para limitar el alcance de la búsqueda con un subsistema:
$ resultSet = $ finder -> find (( new Query ( ' content ' ))-> setInstanceId ( 1 ));
foreach ( $ resultSet -> getItems () as $ item ) {
// first iteration only:
$ item -> getId (); // 'id_1'
$ item -> getInstanceId (); // 1
}
Es una práctica común resaltar las palabras encontradas en los resultados de búsqueda. Puede obtener el título resaltado:
$ resultSet = $ finder -> find ( new Query ( ' title ' ));
$ resultSet -> getItems ()[ 0 ]-> getHighlightedTitle ( $ stemmer ); // 'Test page <i>title</i>'
Este método requiere la lematizadora, ya que tiene en cuenta la morfología y resalta todas las formas de las palabras. De forma predeterminada, las palabras están resaltadas en cursiva. Puede cambiar la plantilla de resaltado llamando $finder->setHighlightTemplate('<b>%s</b>')
.
Los fragmentos son pequeños fragmentos de texto que contienen palabras encontradas y que se muestran en una página de resultados de búsqueda. Rose procesa el contenido indexado y selecciona las oraciones que mejor coinciden.
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>.'
Las palabras de los fragmentos se resaltan de la misma manera que en los títulos.
Si crear fragmentos lleva mucho tiempo, intente utilizar la paginación para reducir la cantidad de fragmentos procesados.
Las instancias pueden resultar útiles para restringir el alcance de la búsqueda.
Por ejemplo, puedes intentar indexar publicaciones de blog con instance_id = 1
y comentarios con instance_id = 2
. Luego puede ejecutar consultas con diferentes restricciones:
(new Query('content'))->setInstanceId(1)
busca en publicaciones de blog,(new Query('content'))->setInstanceId(2)
busca a través de comentarios,(new Query('content'))
busca en todas partes. Al indexar, si omite instancia_id o proporciona instance_id === null
, se utilizará un valor 0
internamente. Dicho contenido solo puede coincidir con consultas sin restricciones de id de instancia.
Rose está diseñada para sitios web y aplicaciones web. Admite el formato HTML del contenido de forma predeterminada. Sin embargo, es posible ampliar el código para que admita otros formatos (por ejemplo, texto sin formato, rebajas). Esto se puede hacer creando un extractor personalizado:
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 tiene la capacidad de identificar elementos similares dentro del conjunto completo de elementos indexados.
Considere un escenario en el que tiene un blog y sus publicaciones están indexadas usando Rose. Esta característica particular le permite elegir un conjunto de otras publicaciones para cada publicación individual, lo que permite a los visitantes explorar contenido relacionado.
La estructura de datos dentro del índice de texto completo es adecuada para la tarea de seleccionar publicaciones similares. En pocas palabras, la búsqueda normal implica seleccionar publicaciones relevantes en función de las palabras de una consulta de búsqueda, mientras que las recomendaciones de publicaciones implican seleccionar otras publicaciones en función de las palabras presentes en una publicación determinada.
Puede recuperar recomendaciones invocando el siguiente método:
$ 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.',
// ],
Nota
Las recomendaciones son compatibles con bases de datos MySQL y PostgreSQL. No están implementados en SQLite debido al soporte limitado de SQL.