Блог компании Softline / Настройка обработки документов на FAST

в 6:24, , рубрики: fast, softline, web-разработка

Одна из задач при интеграции сторонней поисковой машины в систему — это настройка процесса обработки исходных документов (грубо говоря, индексирования). Сложность настройки такого процесса зависит от функциональных требований к системе поиска и возможностей поисковой машины. Настройка может как ограничиться парой кликов в админке поисковой машины, так и вылиться в написание собственных процедур, скриптов и т.д. Если стандартным возможностям системы (тем более если ее код не может быть модифицирован) мы привыкли доверять, то для собственных скриптов хотелось бы иметь тесты, реализация которых не всегда предусмотрена движком.
<a rel="nofollow" name="habracut">
Мы столкнулись с необходимостью реализации поиска на платформе MS FAST ESP 5.3. Этот серьезный движок имеет внушительные возможности кастомизации обработки документов, некоторые из которых мы затронули в своем проекте. В-общем-то, мы хотим поделиться нашим способом тестирования кастомных стейджей на этом движке.

Документация достаточно хорошо описывает процесс создания стейджей. Мы не будем ее пересказывать, ограничимся лишь сведениями, необходимыми для понимания изложенного.
В терминологии FAST ESP вся последовательность действий, которая должна быть выполнена при индексировании одного документа, называется Pipeline, а отдельные действия — Stage. Stage запускается в определенном контексте, с которым может взаимодействовать, одним из элементов которого является документ. К примеру, stage может считывать и записывать атрибуты обрабатываемого документа. Схематично весь процесс обработки документов выглядит так:

Блог компании Softline / Настройка обработки документов на FAST

Стейдж представлен в виде двух файлов — xml-спецификации и реализации (в FAST ESP 5.3 реализация предусматривает использование языка python v.2.3).

Ниже пример стейджа, который записывает в поле quality значение 500, если атрибут документа hotornew имеет значение true.

 <processors>  <processor>   <load module="processors.SetOnEqual" class="SetOnEqual"/>   <desc>Set high rank to documents, which have HotOrNew = yes   </desc>   <config>         <param name="Input" value="hotornew" type="str" />         <param name="Output" value="quality" type="str" />         <param name="InputFieldValue" value="true" type="str" />         <param name="OutputFieldValue" value="500" type="int" />            </config>   <ops>     <add/>   </ops>  </processor> </processors> 

(спецификация непосредственно в тестах не участвует, приведена для целостности картинки)

from docproc import Processor, DocumentException,  ProcessorStatus   class SetOnEqual(Processor.Processor):       def ConfigurationChanged(self, attributes):          self.input = self.GetParameter('Input')          self.output = self.GetParameter('Output')          self.inputfieldvalue = self.GetParameter('InputFieldValue')         self.outputfieldvalue = self.GetParameter('OutputFieldValue')           def Process(self, docid, document):          testField = str(document.GetValue(self.input, None))         if testField == str(self.inputfieldvalue):             output = int(self.outputfieldvalue)             document.Set(self.output,output)         else:                 document.Set(self.output, 0)                 return ProcessorStatus.OK 

Для того, чтобы проверить работу созданного стейджа в родном контексте обработки документа, необходимо проделать последовательность действий, указанную в документации:
1. Выложить в определенные каталоги файлы спецификации и реализации;
2. Перезапустить службу обработки документов — Document Processor (procserver. при запуске он компилирует код стейджей);
3. Включить новый стейдж в pipeline;
4. Проиндексировать тестовый документ;
5. Посмотреть на результат обработки документа (можно вывести в лог-файл, а можно “найти” новый документ через стандартный фронтенд и посмотреть все атрибуты документа).

В случае, если мы не получили ожидаемого результата (к примеру в документе выставили поле hotornew = true, a значение поля Quality так и не изменилось), нам придется заняться отладкой, что означает:
— Поискать ошибку в логе procserver’a;
— Проконтролировать, сделал ли конкретно наш стейдж то, что от него просили, поставив стейджи Spy до и после выполнения тестируемого стейджа. (Spy выгружает дамп документа вместе с его атрибутами в файл на диске);
— Поискать ошибку в коде стейджа.

После того как ошибка поправлена, нужно опять проверить — т.е. опять выполнить шаги 1, 2, 4, 5.
Это муторно. Удобнее отлаживать код стейджа “как есть” привычными методами, например в unit-тесте:

Блог компании Softline / Настройка обработки документов на FAST

Поэтому для “воссоздания” контекста мы сделали примитивные моки классов, с объектами которых работает стейдж:

class Document(object):     """     Mock сущности Document     """          def GetValue(self, name, default):         return getattr(self, name, default)          def Set(self, field, value):         setattr(self, field, str(value))   class Processor (object):     """     Mock сущности Processor     """      def GetParameter(self, name):         return getattr(self, name)      def Set(self, field, value):         setattr(self, field, str(value)) 

В реальности сущность document предоставляет и другие методы. Мы ограничились теми, что используем.
Теперь можно писать/отлаживать/тестировать стейдж без поискового движка:

import unittest import docproc.Processor as proclib from docproc import ProcessorStatus import SetOnEqual  class testSetOnEqual(unittest.TestCase):         def setUp(self):         self.stage = SetOnEqual.SetOnEqual()         self.stage.Set('Input', 'hot')         self.stage.Set('Output', 'quality')         self.assertEquals(self.stage.GetParameter('Input'), 'hot')         self.assertEquals(self.stage.GetParameter('Output'), 'quality')            def test_true(self):         self.stage.Set('InputFieldValue', 'true')         self.stage.Set('OutputFieldValue', '600')         doc = proclib.Document()         doc.Set('hot', 'true')                  self.stage.ConfigurationChanged('')         status = self.stage.Process("docid", doc)         self.assertEquals(status, ProcessorStatus.OK)         self.assertEquals(doc.GetValue('quality', ""), '600')              def test_false(self):         self.stage.Set('InputFieldValue', 'true')         self.stage.Set('OutputFieldValue', '600')         doc = proclib.Document()         doc.Set('hot', 'no')                  self.stage.ConfigurationChanged('')         status = self.stage.Process("docid", doc)         self.assertEquals(status, ProcessorStatus.OK)         self.assertEquals(doc.GetValue('quality', ""), '0')                   def suite():      suite = unittest.TestSuite()     suite.addTest(unittest.makeSuite(testSetOnEqual))     return suite       if __name__ == "__main__":    unittest.main() 

Код целиком есть в архиве.

Что нам дал такой подход:
— Упрощение жизни себе (здорово экономит время и позволяет не отходить от практики модульного тестирования);
— Упрощение жизни тестировщику.

Автор:
Лия Шабакаева
Ведущий разработчик
Департамент разработки Softline
Автор:

Поделиться

* - обязательные к заполнению поля