вторник, декабря 21, 2010

Установка Sphinx 1.10-beta в Fedora 13

Shpinx 0.9.9-1 есть в репозиториях, поэтому для установки этой версии достаточно yum install sphinx

Для установки Sphinx 1.10-beta выкачиваем здесь, или из svn. Смотрим мануал по установке
Будем ставить по максимуму, то есть w/MySQL+PgSQL+libstemmer+id64 support. Что должно быть:
yum install mysql-server mysql-devel postgresql postgresql-devel gcc-c++
Далее 4 простых шага:
1. Выкачиваем sphinx-1.10-beta.tar.gz, распаковываем
wget http://sphinxsearch.com/downloads/sphinx-1.10-beta.tar.gz
tar xzvf sphinx-1.10-beta.tar.gz
cd sphinx-1.10-beta
2. Выкачиваем libstemmer_c.tgz, распаковываем в папку libstemmer_c внутри sphinx-1.10-beta
wget http://snowball.tartarus.org/dist/libstemmer_c.tgz
tar xzvf libstemmer_c.tgz
3. Конфигурируем по максимуму
./configure --prefix=/usr/local/sphinx --with-mysql --with-mysql-includes=/usr/include/mysql --with-mysql-libs=/usr/lib/mysql --with-pgsql --with-pgsql-includes=/usr/include --with-pgsql-libs=/usr/lib/pgsql --enable-id64 --with-libstemmer
4. make
5. make install

6. Создаем /etc/init.d/searchd или берем уже установленный от 0.9.9-1 и корректируем путь к конфигу
#!/bin/sh
#
# sphinx searchd Free open-source SQL full-text search engine
#
# chkconfig:   - 20 80
# description: Starts and stops the sphinx searchd daemon that handles \
#        all search requests.

### BEGIN INIT INFO
# Provides: searchd
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Should-Start: $remote_fs
# Should-Stop: $remote_fs
# Default-Start: 
# Default-Stop: 0 1 2 3 4 5 6
# Short-Description: start and stop sphinx searchd daemon
# Description: Sphinx is a free open-source SQL full-text search engine     
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

exec="/usr/local/sphinx/bin/searchd"
prog="searchd"
config="/usr/local/sphinx/etc/sphinx.conf"
username="sphinx"

lockfile=/var/lock/subsys/searchd

start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    daemon --user=$username $exec --config $config
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    # run checks to determine if the service is running or use generic status
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?



Все, осталось переименовать и поправить конфиг в /usr/local/sphinx/etc/sphinx.conf
проиндексировать
indexer --all
и запустить сервис
service searchd start

PS: к сожалению, обнаружил неприятную багу (симптомы аналогичны, кажется проявляется только для type = pgsql) с индексатором в sphinx-1.10-beta и в текущей версии. При этом indexer из 0.9.9 работает как надо. Приходится searchd использовать из sphinx-1.10-beta (Server version: 1.10-id64-beta (r2420)) или текущей development версии (Server version: 1.11-id64-dev (r2617)), а indexer из 0.9.9.
Другая проблема - работа sphinx на протоколе mysql41 с mysql jdbc-драйвером. В текущей development версии (Server version: 1.11-id64-dev (r2617)) он просто виснет на DriverManager.getConnection. При этом в версии sphinx-1.10-beta (Server version: 1.10-id64-beta (r2420)) все нормально.

понедельник, декабря 20, 2010

Scala/Lift/Mapper и SphinxQL 1.10-beta

Вчера возникла задача подключить Sphinx для полнотекстового поиска к проекту на Scala\Lift. Поскольку начиная с версии 0.0.9 Sphinx поддерживает работу по протоколу MySQL 10 версии (не забываем listen = localhost:3307:mysql41 в конфигурации Sphinx), то логичным было подключить его через стандартный jdbc-драйвер mysql MySQL Connector/J версии 5.1.14 и использовать в запросах SphinxQL. Как обычно бывает, сразу все не завелось даже в самом элементарном случае, но опыт других (раз, два), подсказал направление движения. Как стало ясно, дополнительные параметры characterEncoding и maxAllowedPacket в строке подключения "jdbc:mysql://127.0.0.1:3307?characterEncoding=utf8&maxAllowedPacket=512000" сделают свое дело. Однако попытка определения стандартного StandardDBVendor в Lift с такой строкой подключения неизменно приведет к Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: MySQL Versions Older than 3.23.15 do not support transactions. Ковыряние в сырцах com.mysql.jdbc.Connection показало наличие в public void setAutoCommit(boolean autoCommit) кидания new SQLException("MySQL Versions Older than 3.23.15 "+"do not support transactions", "08003") при условии transactionsSupported!=true && autoCommit == false && this.relaxAutoCommit == false. Сырцы net.liftweb.mapper, в частности StandardDBVendor, ProtoDBVendor показали что имеется многократное setAutoCommit(false) в разных местах, как то: DB.newConnection, ProtoDBVendor.testConnection, ProtoDBVendor.newConnection и т.д. Переписывание классов показалось нецелесообразным и дополнительное исследование параметров jdbc-драйвера mysql показало наличие параметра relaxAutoCommit, которое дословно отвечает за "If the version of MySQL the driver connects to does not support transactions, still allow calls to commit(), rollback() and setAutoCommit() (true/false, defaults to 'false')?" и по умолчанию его значение равно false. Параметр работает, добавление relaxAutoCommit=true решает проблему.
Следующий тест должен проходить:

import java.sql.*;

public class TestSetAutoCommitWithSphinx {

      public static void main(String[] args) throws SQLException {
  Connection con = null;
  String driver = "com.mysql.jdbc.Driver";
  String user = "root";
  String pass = "";
  ResultSet rs = null;
  ResultSetMetaData rsmd = null;

  try {
   Class.forName(driver);
  } catch (Exception e) {
   e.printStackTrace();
  }
        // relaxAutoCommit important if you setAutoCommit(false) with SphinxQL
  con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3307?characterEncoding=utf8&maxAllowedPacket=512000&relaxAutoCommit=true", user, pass);

        // This throw com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: MySQL Versions Older than 3.23.15 do not support transactions
        // without relaxAutoCommit=true in connectionstring 
        con.setAutoCommit(false);

        Statement s = con.createStatement();
        rs =s.executeQuery("select @id as search_id, @weight as search_weight from phoneindex WHERE MATCH('John')");

  rsmd = rs.getMetaData();
  int cc = rsmd.getColumnCount();
  for (int i = 1; i <= cc; i ++)
   System.out.println(rsmd.getColumnName(i));

  while (rs.next()) {
   System.out.println("Id: " + rs.getInt(1) + ", Weight: " + rs.getInt(2));
  }
  rs.close();
 }
}
Cледующая проблема с интеграцией Lift/Mapper и SphinxQL - это реализация протокола mysql в SphinxQL, которая возвращает resultset с полями, имеющими sqltype=-2, то есть BINARY. При меппинге бинарных полей методами Lift/Mapper типа DB.exec и DB.runQuery вызывается метод resultSetTo(rs: ResultSet): (List[String], List[List[String]]), который вызовом DB.asString приводит все в строки. От приведения BINARY в строку через RecordSet.getObject ничего хорошего не получается. Единственные методы, которые возвращают честный ResultSet это def exec[T](db: SuperConnection, query: String)(f: (ResultSet) => T): T и def exec[T](statement: PreparedStatement)(f: (ResultSet) => T): T, поэтому имеется только две конструкция с использованием net.liftweb.mapper.DB, которые будут работать:
DB.use(EventTextSearchDB) { conn =>
          DB.exec(conn,"select * from eventindex WHERE MATCH('Это')") { rs =>
            while (rs.next) {
              // rs.getInt(1) for 32bit doc_id, rs.getLong(1) for 64bit doc_id
              println("Id: " + rs.getLong(1) + ", Weight: " + rs.getInt(2))
            }
          }
          DB.prepareStatement("select * from eventindex WHERE MATCH(?)",conn) { stmt =>
            stmt.setString(1,"Это")
            val rs=stmt.executeQuery
            while (rs.next) {
              println("Id: " + rs.getLong(1) + ", Weight: " + rs.getInt(2))
            }
          }
        }

Кажется все.

PS: Может быть поиск решения работы с Sphinx из Scala/Lift/Mapper и не стоил того - проще было прикрутить любой имеющийся connection pool и сделать свои обертки, но стандартизация требует жертв.

вторник, декабря 14, 2010

VirtualBox 2.6.34.7-63.fc13.i686.PAE VBoxVMM.so: cannot open shared object file

Изредка тестирую web-приложения в Windows под VirtualBox. Сегодня обнаружил, что он перестал запускаться с сообщением VirtualBox: supR3HardenedMainGetTrustedMain: dlopen("/usr/lib/virtualbox/VirtualBox.so",) failed: VBoxVMM.so: cannot open shared object file: No such file or directory

Помогло
find /usr/lib/virtualbox/ -name \*.so -exec ln -s -t /lib '{}' ';'
И не надо забывать чтобы пользователь был в группе vboxusers

Мой список блогов