sorgalla.com

PHP, Zend Framework, Datenbanken und was sonst noch so anfällt.

Sphinx und SphinxSE ins Zend Framework integrieren

with 3 comments

Serie

Nachdem Sphinx und SphinxSE installiert ist, geht es diesmal um die Integration in ein Zend Framework-Projekt. Dazu gehört die Erstellung einer Konfigurationsdatei und ein Kommandozeilen-Skript zum Starten und Stoppen des Sphinx-Suchdämons und zum Generieren des Suchindexes.

Den Code zum Artikel gibts auf github.

Das Zend Framework ist nicht enthalten und muss noch nachinstalliert werden. Entweder man lädt sich die aktuelle Version herunter und kopiert oder linkt den Zend-Ordner ins library-Verzeichnis oder man installiert es per PEAR. Den (inoffiziellen) PEAR Channel gibts unter http://pear.zfcampus.org.

Die Konfigurationsdatei

Die Konfigurationsdatei von Sphinx ist die Schaltzentrale und enthält alle Optionen für den Dämon, den Indexer, die Indizes und deren Datenquellen. Für unser Beispielprojekt nutzen wir eine einfache Variante mit Grundeinstellungen. Der Clou ist, dass die Konfigurationsdateien von jeder beliebigen Skriptsprachen verarbeitet werden kann. Einfach am Anfang der Datei den entsprechenden Shebang setzen.

Die Datei liegt in application/configs/sphinx.conf:

#!/usr/bin/env php
<?php
 
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/..'));
 
// Define application environment
//
// Use `export APPLICATION_ENV=development` or edit /etc/environment
// to change the application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
 
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../../library'),
    get_include_path(),
)));
 
/** Zend_Application */
require_once 'Zend/Application.php';
 
// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
$config = $application->getOptions();
?>
source posts
{
    type                    = mysql
 
    sql_host                = <?php echo $config['resources']['db']['params']['host'] . "\n"; ?>
    sql_user                = <?php echo $config['resources']['db']['params']['username'] . "\n"; ?>
    sql_pass                = <?php echo $config['resources']['db']['params']['password'] . "\n"; ?>
    sql_db                  = <?php echo $config['resources']['db']['params']['dbname'] . "\n"; ?>
    # sql_port               = 3306    # optional, default is 3306
 
    sql_query_pre           = SET NAMES utf8
 
    sql_query               = \
        SELECT posts.id, posts.category_id, posts.title, posts.content, UNIX_TIMESTAMP(posts.created) AS created, \
               categories.name AS category_name, \
               GROUP_CONCAT(tags.tag SEPARATOR ', ') AS tags \
          FROM posts \
          JOIN categories ON (categories.id = posts.category_id) \
     LEFT JOIN posts_tags ON (posts_tags.post_id = posts.id) \
     LEFT JOIN tags ON (tags.id = posts_tags.tag_id) \
      GROUP BY posts.id
 
    sql_attr_uint           = category_id
    sql_attr_timestamp      = created
 
    sql_query_info          = \
        SELECT posts.id, posts.category_id, posts.title, posts.content, posts.created, \
               categories.name AS category_name, \
               GROUP_CONCAT(tags.tag SEPARATOR ', ') AS tags \
          FROM posts \
          JOIN categories ON (categories.id = posts.category_id) \
     LEFT JOIN posts_tags ON (posts_tags.post_id = posts.id) \
     LEFT JOIN tags ON (tags.id = posts_tags.tag_id) \
         WHERE posts.id=$id
}
 
index posts
{
    source                  = posts
    path                    = <?php echo $config['sphinx']['index']['path']; ?>/posts
    docinfo                 = extern
    html_strip              = 1
    charset_type            = utf-8
    # Character table for german (from http://www.sphinxsearch.com/forum/view.html?id=19)
    charset_table           = 0..9, A..Z->a..z, _, a..z, U+C4->U+E4, U+D6->U+F6, U+DC->U+FC, U+DF, U+E4, U+F6, U+FC
}
 
indexer
{
    mem_limit               = 32M
}
 
searchd
{
    listen                  = <?php echo $config['sphinx']['searchd']['listen'] . "\n"; ?>
    log                     = <?php echo $config['sphinx']['searchd']['log'] . "\n"; ?>
    query_log               = <?php echo $config['sphinx']['searchd']['query_log'] . "\n"; ?>
    read_timeout            = 5
    max_children            = 30
    pid_file                = <?php echo $config['sphinx']['searchd']['pid_file'] . "\n"; ?>
    max_matches             = 1000
    seamless_rotate         = 1
    preopen_indexes         = 0
    unlink_old              = 1
}

Was die einzelnen Optionen bedeuten, kann man in der Dokumentation gut nachlesen. Ich will hier nur auf paar Besonderheiten eingehen:

  • Der PHP-Abschnitt am Anfang der Datei nutzt Zend_Application um die application.ini zu laden.
  • Im Abschnitt source posts nutzen wir die ausgelesenen Optionen um die Zugangsdaten für die Datenbank zu setzen. Diese können dann global in der application.ini verwaltet werden.
  • Im Abschnitt index posts und searchd verwenden wir ebenfalls Optionen aus der application.ini. Das sind vor allem Pfadangaben für den Suchindex und Logdateien und an welcher IP und/oder Port der Suchdämon lauschen soll. Diese Angaben können wir somit pro APPLICATION_ENV anpassen.

Das Kommandozeilen-Skript für Sphinx

Um den Suchindex zu erstellen und den Suchdämon zu starten und zu stoppen, enthält das Projekt das Kommandozeilen-Skript in scripts/sphinx. Der Aufruf erfolgt so:

$ ./scripts/sphinx COMMAND ENVIRONMENT

COMMAND

Folgende Kommandos sind möglich:
start Startet den Suchdämon.
stop Stoppt den Suchdämon.
restart Startet den Suchdämon neu.
index-all Erstellt alle in application/configs/sphinx.conf definierten Suchindizes.

ENVIRONMENT

Gibt APPLICATION_ENV an, entspricht also define('APPLICATION_ENV', 'production'); in z. B. der index.php. Somit wird der entsprechende Abschnitt in application/configs/application.ini genutzt. Wenn nicht angegeben, wird standardmäßig production verwendet.

Beispiele

Startet den Suchdämon mit APPLICATION_ENV=production:

$ ./scripts/sphinx start production

Erstellt alle Suchindizes mit APPLICATION_ENV=development:

$ ./scripts/sphinx index-all development

Somit haben wir nun unser Zend Framework-Projekt präpariert um mit Sphinx zu arbeiten. Auf den Suchindex lässt sich nun ganz einfach, z. B. per Zend_Db_Select, zugreifen:

$query = 'Mein Suchbegriff';
$select = $db->select();
$select->from('posts')
       ->joinInner('sphinx', 'sphinx.id = posts.id')
       ->where('sphinx.query = ?', $query . ';mode=any;sort=extended:@weight desc, @id asc;limit=10;offset=0;index=posts');
$result = $select->query()->fetchAll();

Links zum Thema

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit

Written by jan

Januar 18th, 2010 at 11:58 am

Posted in Zend Framework

Tagged with , , ,

3 Responses to 'Sphinx und SphinxSE ins Zend Framework integrieren'

Subscribe to comments with RSS or TrackBack to 'Sphinx und SphinxSE ins Zend Framework integrieren'.

  1. [...] sorgalla.com wird auch beschrieben, wie SphinxSE mit dem Zend Framework integriert werden kann. Feine Sache! [...]

  2. Vielen Dank für diesen guten Artikel.
    Gibt es noch einen Link zu Benchmarks von MySQL oder o.ä. im Vergleich zu Sphinx(SE)?

    David

    19 Apr 10 at 18:53

  3. @David: Einfach mal googeln, da findet sich einiges. Im Sphinx-Blog gab’s vor kurzem Benchmarks von Expressions im Vergleich zu MySQL.

    jan

    19 Apr 10 at 20:05

Leave a Reply