26 May 2013

Fixing Sphinx wordforms

Sphinx wordforms feature has a drawback: the stemmer skips "destination" words. In this post I'll show a quick and dirty way to fix a large wordforms file.

Let's assume we have a wordforms file with the following contents:

noisy > noise
noisyyy > noise
Any document having word noisy will be found by searching for noisyyy. And vice versa. Bad news is that the word noise is out of stemming. It means that if we try to search for noise, we'll find only those documents that contain exactly "noise".

Sphinx 2.1.1-beta introduced indextool --morph INDEXNAME option, which applies morphology to the characters given on the standard input, e.g.:

echo 'confidence
> presence' | ~/bin/indextool --morph s3_all
Sphinx 2.1.1-beta (rel21-r3701)
Copyright (c) 2001-2013, Andrew Aksyonoff
Copyright (c) 2008-2013, Sphinx Technologies Inc (http://sphinxsearch.com)

using config file './sphinx.conf'...
dumping stemmed results...
confid presenc
Yes, the output might be more friendly(parsable). It even doesn't support --quiet option at the time. Now we are going to replace the destination words with their stemmed variants. Here is a simple one-shot Perl script for this.
#!/usr/bin/perl
# File: stem-wordforms.pl
use strict;
use warnings;
use Fcntl; # sysopen
use POSIX 'tmpnam';
use IO::Seekable; # seek

sub usage () {
    print "Usage: $0 <filename> [<out_filename>]
<filename>         Path to SphinxSearch wordforms file
<out_filename>   Path to output filename 
";
}

if ($#ARGV < 0) {
    usage;
    exit;
}
my $in_filename  = $ARGV[0];
my $out_filename = $#ARGV > 0 ? $ARGV[1] : $in_filename .".out";
my $tmp_filename = tmpnam();
my $line;
my $n_in_lines = 0;
my $n_out_lines = 0;

sysopen FH_IN, $in_filename, O_RDONLY
    or die("Failed to open `$in_filename`");
sysopen FH_RES, $out_filename, O_CREAT | O_TRUNC | O_WRONLY, 0640
    or die("Failed to open `$out_filename`");
# Open pipe for indextool. We'll write destination wordforms here line by line.
# By means of `tr` command we place a word per line.
open my $fh_indextool, "|-",
"~/bin/indextool -c sphinx.conf --morph s3_all | tr ' ' '\n' > $tmp_filename"
    or (print "Failed\n" and die());

print ">> Stemming to `$tmp_filename`...";
while (<FH_IN>) {
    ++$n_in_lines;

    # Get destination word
    s/^[^\>]+\> // ;
    # Patch: for some reason Sphinx 2.1.1-beta strips `ё` character even if it
    # is declared in charset_table
    s/ё/e/g;
    $line = $_;

    print $fh_indextool $line;
}
close $fh_indextool;
print " OK\n";

print ">> Joining temporary results with the source wordforms... ";
my $got_results = 0;
my $line2;
sysopen(FH_TMP, $tmp_filename, O_RDWR, 0640)
    or die("Failed to open `$tmp_filename`");
seek FH_IN, 0, SEEK_SET;
while (<FH_TMP>) {
    $line = $_;

    if ($got_results == 0 && m/^results\.\.\./) {
        print "Got results... ";
        $got_results = 1;
        next;
    }
    $got_results or next;

    last if !($line2 = <FH_IN>);
    $line2 =~ s/[^\>]+$//;
    print FH_RES $line2 , " ", $line;
    ++$n_out_lines;
}
unlink $tmp_filename or print "Failed to unlink $tmp_filename\n";

$n_in_lines != $n_out_lines and die("* Failed! Number of lines of `$in_filename` and `$out_filename` doesn't match!\n");

print "OK\nDone\n";

close FH_IN;
close FH_RES;
close FH_TMP;
Not very nice script, but hopefully will help someone. You may want to adapt it for your configuration. Usage:
$ ./stem-wordforms.pl wordforms_myspell_ru_RU_UTF-8.txt out
>> Stemming to `/tmp/file7AawtG`... OK
>> Joining temporary results with the source wordforms... Got results... OK
Done

10 December 2012

Accessing server vhosts on the VirtualBox guests

This post will probably help you, if you are searching for way to access an Apache/Nginx vhost on VirtualBox's guest. Let's assume we have vhost mega8080 listening on port 8080. The following makes it available for Windows XP guest.

Edit vhost configuration

Vhost configuration file like /etc/apache2/sites-available/localhost should listen to port 8080:

ServerName server.megahost
NameVirtualHost 127.0.0.3:8080


DocumentRoot /var/www/megahost8080
ServerName megahost8080

Register IP

In our sample /etc/hosts should have the following like:

127.0.0.3	megahost8080

Relay port 8080 connections to IP 127.0.0.3

# iptables -t nat -I PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 127.0.0.3
# iptables -t nat -A OUTPUT -p tcp --dport 8080 -j DNAT --to-destination 127.0.0.3
We need this because in Windows XP ipconfig outputs:
IPv4Address: 10.0.2.15
Default Gateway: 10.0.2.2

We need port forwarding because it won't work if configure our vhost to listen to 10.0.2.15 directly.

Simplest way to configure network for guest is to keep it's default NAT configuration :)

Network adapter: 
 - attached to: NAT 
 - type: PCnet-FAST III (NAT)

Forward port 8080 connections through TCP in VBox

$ VBoxManage setextradata "winxp" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/http/Protocol" TCP
$ VBoxManage setextradata "winxp" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/http/GuestPort" 8080
$ VBoxManage setextradata "winxp" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/http/HostPort" 8080
Or, in new versions, just set it up via GUI: Settings - Network - Port Forwarding.

Bind guest IP to the hostname

File C:\windows\system32\drivers\etc\hosts(or similar) should contain line like the following:

10.0.2.2	megahost8080

Test it

Go to http://megahost8080:8080

07 November 2012

Upgrading to Newest Version of an App Which Still Is Not Available In the Gentoo Portage

Sometimes you need new version of an app, but it is not yet availlable via Gentoo's portage(or overlays). If you want to keep things organized, you have to make package yourself. In some distros it is done easily with `checkinstall` utility, which helps to produce Debian, RPM or Slackware packages. In Gentoo we have make a ebuild ourselves.

However, ebuild tool and existing ebuilds in PORTDIR(usually /usr/portage) make it pretty easy too. I'll show it with example.

Let's say, I have to upgrade app-misc/sphinx to version 2.0.6. But even after emerge --sync the latest ebuild available is /usr/portage/app-misc/sphinx/sphinx-2.0.5.ebuild. For this, we'll do the following: 1) Add our custom portage directory 2) Copy and modify sphinx-2.0.5.ebuild in our brand new portage dir 3) emerge the new version, pulling the code from the official application maintainer's site

Add new portage overlay dir:

# mkdir -p /var/lib/layman/my_ebuilds
# vim /etc/portage/make.conf
# ...
PORTDIR_OVERLAY="${PORTDIR_OVERLAY} /var/lib/layman/my_ebuilds"
# ...

Copy existing ebuild:

# cp /usr/portage/app-misc/sphinx/sphinx-2.0.5.ebuild /var/lib/layman/my_ebuilds/app-misc/sphinx/sphinx-2.0.6.ebuild
# vim /var/lib/layman/my_ebuilds/app-misc/sphinx/sphinx-2.0.6.ebuild
... change version, URIs etc. if needed (in my case it detects version automatically)

Build ebuild manifest(this will fetch file from the Web):

# cd /var/lib/layman/my_ebuilds/app-misc/sphinx
# ebuild sphinx-2.0.6.ebuild manifest

Finally upgrade to the new version:

# emerge -Duva app-misc/sphinx

That's it! Enjoy:)

References

1. Gentoo WIKI: Writing Ebuilds

04 November 2012

Speeding Up Copy Process Between Two Hard Drives

cp command is not suitable for large data transfers between two hard drives. It makes about 10..100KB/sec. Obviously, it will take 29 hours to copy 10GB with 100KB/sec.

There are many ways to speed up copying process -- using USB, Firewire, Ethernet etc. But if everything is done on a local machine, rsync is very effective and simple to use. For example, the following shows how to copy files over the virtual loopback device:

$ mkdir -p /mnt/hdd
$ sudo mount /dev/sdbX /mnt/hdd
$ rsync -az user@localhost:/some/folder/* /mnt/dest-hdd/

a("archive mode") option takes care of permissions, ownership, group, symlinks and so. z instructs rsync to use compression.

10 May 2012

/var/run/mysqld is removed after each reboot?

After recent upgrade on my Gentoo box I've accidently got /var/run/mysqld directory removed. The socket path pointed there, and, of course, mysqld denied to launch. The same thing happened some time ago on Ubuntu and openSUSE. I've no clue what makes it(mysqld? rc script?) remove the directory. But I've got at least two simple fixes for that and wanna share it in this post.

Fix #1

Just change path to the socket in /etc/mysql/my.cnf and get rid of these upgrade issues:

socket = /tmp/mysqld.sock
I have it in client and mysqld sections.

Fix #2

Change the runlevel script. In Gentoo it looks like the following:

checkconfig() {
    if [ ! -d /var/run/mysqld ] ; then
        checkpath -d -m 755 -o mysql:mysql /var/run/mysqld
    fi
    if [ -z "${MYSQL_PERMS_OK}" ] && [ "$(stat -c %a /var/run/mysqld)" != "755" ] ; then
        ewarn "mysqld run dir is not world readable, you should reset the perms:"
        ewarn "chmod 755 /var/run/mysqld"
        ewarn "To disable this warning, set 'MYSQL_PERMS_OK' in /etc/conf.d/mysql"
    fi
}
start() {
    checkconfig
    # ...
}
You should have got it. checkconfig is called on at the very beginning of /etc/init.d/mysql start handler.

That's it. I hope this saves someone's time.

15 December 2011

Installing ImageMagick with DejaVu support

I've had troubles with DejaVu fonts in ImageMagick. Almost everything with -font 'DejaVu-Sans-Condensed' failed. Well, it was searching for the font, consuming much of CPU resources, and used default one afterwards. In this post I'll show how to compile ImageMagick from source with DejaVu support. Althouth it may seem trivial, the process may sometimes be tricky.

First off, install FreeType dev package. It should be called libfreetype*-dev or so. For instance, in Debian:

$ sudo apt-get install libfreetype6-dev

Make sure you have DejaVu font installed. Package name should be named somewhat like 'ttf-dejavu'. In Debian you can install it as follows:

$ sudo apt-get install ttf-dejavu-core ttf-dejavu ttf-dejavu-extra

Download the source

Download tarball from http://www.imagemagick.org/script/download.php and unpack it.

Find font directories

Figure out the main directory with fonts and a directory with DejaVu fonts, and specify them in configuration:

$ ./configure --with-freetype=yes --with-djvu=yes \
--with-fontpath=/usr/share/fonts/truetype \
--with-dejavu-font-dir=/usr/share/fonts/truetype/ttf-dejavu 

Compile and install:

$ make
$ sudo make install 
# or 
# sudo make checkinstall
# whatever preferred/appropriate.

ldconfig

I had to make the follownig for my /usr/local prefix:

$ sudo ldconfig
Likely, you should do it also.

Verify

Verify that ImageMagick recognizes DejaVu:

$ identify -list font | grep -i dejavu
This should output a list with installed DejaVu fonts.

I hope this will be helpful for someone.

11 October 2011

eio - a new PHP extension for asynchronous POSIX I/O

Eio is a new PECL extension for asynchronous POSIX I/O.

Eio provides interface for the libeio library. It means that each POSIX call runs in a separate thread. It is important to aware that the order of ungrouped requests is not precisely known. However, libeio, as well, as eio, supports complex call creation to accumulate a set of regular eio_* requests in a single group request. This allows to create a group request ex. to open, read and close a file.

Currently Windows platforms are not supported.

Any extension-specific suggestions are welcome :)