Turtle

 
 
 
   РАСШИРЕННЫЙ ПОИСК
   ПОИСК ПО ФРАГМЕНТУ
   ПОМОЩЬ
   ПРОСТАЯ ФОРМА
 
 СИНОНИМЫ   ВСЕ ФОРМЫ СЛОВ
 Добавить   Архитектура   Запросы сейчас   Цифры и факты   FAQ   Кнопка поиска   Сделать стартовой 

Multilingual Morphology Module MMM/1.0

Статус этого документа.

Этот документ описывает внутренний для компании Stack Technologies Ltd. модуль многоязыковой морфологической поддержки в системе накопления и поиска информации. Документ предназначен для служебного использования. Этот документ может и должен являться предметом обсуждения, с последующим внесением изменений. Документ не ограничивает возможность разработчиков компании использовать другие морфологические пакеты.

Copyright Notice

Copyright © Stack Technologies Ltd. (2001). All Rights Reserved.

Содержание.

1. Назначение.
2. Основные характеристики.
3. Глобальные переменные.
4. Основные функции.
5. Пример использования.
6. Форматы файлов конфигурации.

1. Назначение.

Модуль входит в основную библиотеку поисковой системы libturtle.a. Основным назначением модуля является определение принадлежности термина (слова) к конкретному языку и раскрытие всех возможных морфологических форм термина для различных языков. Библиотека написана на языке программирования "C".

2. Основные характеристики.

В основе модуля были использованы данные, взятые из словарей ispell, к которым были добавлены слова и формы, полученные из других источников. В настоящий момент модуль может работать с 24 языками и возможно подключение новых языков. В качестве модели хранения данных используется пакет Berkeley DB версии 3.3.11. Выбор модели хранения на диске обусловлен тем, что суммарное количество словоформ языков весьма велико и не представлялось разумным держать все формы в памяти компьютера. Например, типовой накопитель данных - scanner Поисковой Системы - работает на простой Intel-платформе, имея 64MB памяти. В процессе своей работы такой scanner должен определять принадлежность полученного им документа к конкретному языку.

Проводимые тесты показали скорость раскрытия словоформ слов как 20 тыс. слов в секунду. При этом половина слов была словарной, а половина не являлась словарной и не подлежала раскрытию на словоформы. Тесты показали, что именно "неудачные" раскрытия словоформ и составляют самую большую часть работы. Учитывая соотношение размера, занимаемого в памяти, функциональности и скорости работы, решение для накопителей данных было признано удовлетворительным. Модуль находится в файле lib/graber_lang.c.

3. Глобальные переменные.

Модуль не проектировался как отчуждаемый продукт, поэтому при разработке была заложена возможность использования глобальных переменных, входящих в состав конфигурационной структуры многих компонент Поисковой Системы. Модуль требует объявленной структуры TURTLE_PARAMS dmn, объявленной в include/turtle_structs.h. Имя глобальной переменной должно быть именно dmn в вашем модуле, если вы собираетесь использовать эту подсистему. Эта глобальная структура во внешней программе должна быть обязательно проинициализована вызовом функции init_daemoninfo(void).

Модуль использует следующие элементы структуры TURTLE_PARAMS:

char *dmn.dmn_lexemedb
имя файла базы лексем.
char *dmn.dmn_affixdb
имя файла базы суффиксов лексем.
char *dmn.dmn_rootdir
home directory, сочетание dmn.dmn_rootdir/dmn.dmn_lexemedb дает полный путь к файлу базы данных лексем.
int dmn.dmn_stemiterations
максимальное конфигурационное значение количества итераций отделения последней буквы для нахождения псевдоосновы термина в словаре.
char *dmn.dmn_langfile
файл, описывающий включенные в систему языки и их коды. Этот же файл участвует в описании при построении нового словаря.

Во многих программах Поискового комплекса все значения глобальной структуры могут быть описаны в конфигурационном файле, который зачитывается с помощью библиотечной функции read_config(char *conf_name).

4. Основные функции.

void languages_read(void)

Функция имеет несколько назначений. Если файлы базы данных, определенных в элементах структуры dmn.dmn_lexemedb и dmn.dmn_affixdb существуют, то функция зачитывает конфигурацию языков из файла dmn.dmn_langfile и просто открывает эти базы данных для последующей морфологической работы с ними в режиме READ_ONLY. Если же файлы базы данных не существуют, то функция пытается их создать, используя заложенное в dmn.dmn_langfile описание кодов языков и файлов исходных данных для создания словарей. Формат строения dmn.dmn_langfile и файлов исходных данных для создания словарей описаны ниже. Перед выполнением морфологических операций эта функция обязательно должна быть вызвана. При создании новых словарей в конце работы программы обязательно должна быть вызвана функция languages_close().

int *languages_check(unsigned char *word)

Функция возвращает указатель на массив, содержащий ID языков, в которых данное слово было обнаружено. Коды языков определяются в конфигурационном файле dmn.dmn_langfile при создании словарей и при дальнейшей работе не могут быть переопределены в рамках существующих словарей. Перед окончанием работы вызывающей функции указатель на массив следует освобождать с помощью free(). Последний элемент массива всегда имеет значение 0. Таким образом, можно определить конец массива. Если функция возвращает в качестве значения NULL, то это означает, что искомого значения нет в словаре.

int languages_checkword(unsigned char *word, int lang_id)

Функция проверяет принадлежность слова word к языку, определяемому в параметре lang_id. Если слово принадлежит к данному языку, то функция возвращает сам код языка, в противном случае, функция возвращает -1.

unsigned char **languages_expand(unsigned char *word, int32_t **langs, int check_lang, unsigned char *prefix, int prefix_len)

Основная морфологическая функция. Входные параметры:

unsigned char* word
искомое слово.

int32_t **langs
адрес указателя, куда будут помещены коды языка, для которого данное слово обнаружено. Если при вызове этот параметр установить в NULL, то коды языков не будут помещены в массив.

int check_lang
язык, для которого производится морфологическое раскрытие. Если его значение равно 0, то раскрытие производится для всех возможных языков (например слово 'test' существует в различных языках и встречается в различных морфологических формах).

unsigned char *prefix
префикс слова, который при морфологическом анализе будет проигнорирован и добавлен ко всем полученным морфологическим формам. Например, может использоваться для слов, начинающихся с отрицательной приставки 'не'. Значение этого параметра не может быть NULL. Если в его использовании нет необходимости, то вызывайте данную функцию с аргументом строки нулевой длины "".

int prefix_len
длина префикса в символах, описанная выше. Если префикс не используется, то значение этого аргумента должно быть 0. См. пример.

Функция возвращает массив указателей развернутых форм в случае успеха. В случае неудачи возвращаемое значение равно NULL.

void languages_close(void)

Функция окончания работы с морфологическим модулем MMM/1.0.

5. Пример использования.

Пример использования находится в src/scanner/turtle_dict.c Пример не является оптимальным, как программа, но является рабочим действующим.
#include "turtle.h"

TURTLE_PARAMS dmn;
CONNECTION *connects=NULL;

/***************************************************************************/
void exit_func(void)
{
#ifdef USE_LANGUAGES
languages_close();
#endif
}
/***************************************************************************/
int main(int ac, char *av[])
{
extern char *optarg;
char *p, *config_file=strdup("turtle_dict.cf");
int i,test_flag=0,save_flag=0,print_flag=0;
#ifdef USE_LANGUAGES
char str[16*STR_LEN];
int good=0, bad=0;
struct timeval tv1,tv2;
double secs,secs1;
int32_t *theme=NULL;
int lg_id=0;
#endif

if ((p=strrchr(av[0],'/')) != NULL)
        ++p;
else p=av[0];

/*  params structure start initializacion */
init_daemoninfo();

#ifdef USE_SYSLOG
/* Need to write critical errors by syslog */
(void)openlog(p,LOG_NDELAY|LOG_PID,LOG_FACILITY );
#endif

dmn.dmn_progname=p;
(void)atexit(exit_func);

/* Now parse the command line args */
while ((i = getopt(ac, av, "bc:l:p:t")) != EOF)
        switch (i) {
                case 'b':
                        save_flag=1;
                        break;
                case 'c':
                        config_file=optarg;
                        break;
#ifdef USE_LANGUAGES
                case 'l':
                        lg_id=atoi(optarg);
                        break;
#endif
                case 'p':
                        print_flag=atoi(optarg);;
                        break;
                case 't':
                        test_flag=1;
                        break;
                case '?':
                default:
                        turtle_usage();
                }

/* Read and set the current configuration */
if ((dmn.dmn_logfp=open_turtle_file(config_file,"r")) == NULL)
        {
        (void)fprintf(stderr,"read config error: %s %s\n",config_file,
                strerror(errno));
        exit(1);
        }
if (!read_config(dmn.dmn_logfp))
        {
        (void)fprintf(stderr,"Can't read %s\n",config_file);
        exit(1);
        }
fclose(dmn.dmn_logfp);
if (dmn.dmn_logfile && strlen(dmn.dmn_logfile))
        dmn.dmn_logfp=open_turtle_file(dmn.dmn_logfile,"a+");
if (dmn.dmn_rootdir && chdir(dmn.dmn_rootdir) < 0)
        turtle_log(NULL,D_CRIT,"chdir - %s %m",dmn.dmn_rootdir);
#ifdef USE_LANGUAGES
if (save_flag)
        {
        (void)unlink(dmn.dmn_lexemedb);
        (void)unlink(dmn.dmn_affixdb);
        }
languages_read();
(void)fprintf(stderr,"Ready:\n");
(void)gettimeofday(&tv1,NULL);
while (fgets(str,16*STR_LEN,stdin) != NULL)
        {
        unsigned char **lst=NULL;

        chopstr(str);
        if (!test_flag)
                {
/*
                theme=languages_checklang(str);
*/
                if ((lst=languages_expand(str,&theme,lg_id,"",0)) == NULL
                        && theme == NULL)
                        {
                        ++bad;
                        (void)printf("Not expanded\n");
                        continue;
                        }
                ++good;
                (void)printf("languages:");
                if (theme)
                        {
                        for (i = 0; theme[i]; i++)
                                (void)printf(" %s [0x%x]",
                                languages_getname(theme[i]),theme[i]);
                        (void)putchar('\n');
                        free(theme);
                        theme=NULL;
                        }
                else
                        (void)printf("no languages, hmm...\n");
                if (lst)
                        {
                        for (i = 0; lst[i]; i++)
                                {
                                (void)printf("%s ",lst[i]);
                                free(lst[i]);
                                }
                        free(lst);
                        (void)putchar('\n');
                        }
                }
        else
                {
                char *p=strchr(str,' ');
                char old_c='\0';
                if (p)
                        {
                        old_c=*p;
                        *p='\0';
                        }
                if (languages_checkword(str,0) == -1)
                        {
                         ++bad;
                        if (print_flag == 1)
                                (void)printf("%s #\n",str);
                        else if (print_flag == 2)
                                {
                                if (p)
                                        *p=old_c;
                                (void)printf("%s\n",str);
                                }
                        }
                else
                        ++good;
                }
        }
(void)gettimeofday(&tv2,NULL);
secs1=(double)tv1.tv_usec/(double)1000000+(double)tv1.tv_sec;
secs=(double)tv2.tv_usec/(double)1000000+(double)tv2.tv_sec;
secs-=secs1;
if (test_flag)
        (void)fprintf(stderr,"Real steming: %d - in %f sec\n",good+bad,secs);
(void)fprintf(stderr,"total: %d good: %d bad: %d\n",good+bad,good,bad);
#else   /* USE_LANGUAGES */
(void)fprintf(stderr,"program mast be with -DUSE_LANGUAGES compile options\n");
#endif
exit(0);

6. Форматы файлов конфигурации.

Описание языков, известных системе производится в файле, имя которого указано в элементе структуры dmn.dmn_langfile. Вторая позиция может быть использована для указания имени файла сырых данных при создании нового словаря. Ниже приведен текущий рабочий пример этого файла:

#
# language_name language_file   language_id
#
# Attention: don't modify this file without knowing what you realy do
#
english		none 0x01	английский		ru_RU.WINDOWS-1251
german		none 0x02	немецкий		de_DE.ISO_8859-1
french		none 0x03	французский		fr_FR.ISO_8859-1
italian		none 0x04	итальянский		it_IT.ISO_8859-1
spanish		none 0x05	испанский   		es_ES.ISO_8859-1
russian		none 0x06	русский         	ru_RU.WINDOWS-1251
bulgarian 	none 0x07	болгарский		ru_RU.WINDOWS-1251
brazilian  	none 0x08	бразильский     	pt_PT.ISO_8859-1
swedish    	none 0x09	шведский        	sv_SE.ISO_8859-1
norwegian  	none 0x0a    	норвежский      	no_NO.ISO_8859-1
ukrainian  	none 0x0b    	украинский      	ru_SU.WINDOWS-1251
danish     	none 0x0c    	датский         	da_DK.ISO_8859-1
portugues  	none 0x0d    	португальский   	pt_PT.ISO_8859-1
finnish    	none 0x0e    	финский         	fi_FI.ISO_8859-1
esperanto  	none 0x0f    	эсперанто       	ru_RU.WINDOWS-1251
afrikaan   	none 0x10    	африканский     	ru_RU.WINDOWS-1251
czech      	none 0x11    	чешский         	cs_CZ.ISO_8859-2
dutch      	none 0x12    	голландский     	nl_NL.ISO_8859-1
hebrew     	none 0x13    	иврит           	ru_RU.WINDOWS-1251
polish     	none 0x14    	польский        	pl_PL.ISO_8859-2
slovenian  	none 0x15    	словенский      	sl_SI.ISO_8859-2
slovak     	none 0x16    	словацкий       	sl_SI.ISO_8859-2
indonesian 	none 0x17    	индонезийский   	ru_RU.WINDOWS-1251
romanian   	none 0x18    	румынский       	ru_RU.WINDOWS-1251
mat        	none 0xff    	ненормативный   	ru_RU.WINDOWS-1251
Наверх Назад Turtle
 Черепаший Ранк.   Реклама на Turtle   Логотипы   Правовая информация   Конфиденциальность   Контакты 
    ©ЗАО "Группа компаний Стек". 2003-2007