В прошлый раз, когда я принимался за прикручивание поиска в форум, я буквально во втором абзаце "похоронил" штуку под названием Sphinx из-за того, что он, как мне показалось, работает только с MySQL. Андрей Аксенов, автор Сфинкса, в комментариях это заблуждение опроверг, и я оставил у себя пометку в памяти, что надо будет посмотреть на него.

Окончательно же мое желание сформировалось, когда на Highload 2007 мне удалось послушать доклад о Сфинксе и пообщаться с Андреем, который и разрешил все мои оставшиеся вопросы. Помнится, "купила" меня в итоге фраза о том, что он дает большую релевантность в поиске точному совпадению введенной фразы, а не просто близко стоящим словам (или что-то в таком роде :-) ).

В итоге, Cicero теперь имеет поиск, использующий Sphinx. Дальше — традиционый рассказ о реализации.

Bzr-репозиторий http://softwaremaniacs.org/code/cicero/
Работающий форум http://softwaremaniacs.org/forum/

Индексация

Sphinx умеет читать данные из MySQL и PostgreSQL, но также и из пользовательской программы, которая выдает на stdout некий псевдо-XML. Я воспользовался именно этим способом, потому что 1) мне, как я уже упоминал, не хочется привязываться к конкретной СУБД и 2) потому что я хочу индексировать статьи, а искать топики. Поясню второй пункт.

Когда Sphinx индексирует документы в БД, он просит указать в конфигурации SQL-запрос, который будет выдавать строки, которые такими документами и считаются. В них должен быть ID и текст. Все бы хорошо, но у меня в форуме единица информации — целиком топик, а не отдельная статья. Получается, мне нужен запрос, который бы выдавал ID топика и весь его текст, то есть текст всех его статей. Я слишком плохо знаю SQL, чтобы составить такой запрос, поэтому я и написал для этого несложный код, который выдает топики с текстом всех их статей, соединеных вместе:

# Составляет текст топика из текста его статей
def text(topic):
  return ' '.join([a.text for a in topic.article_set.all()])

# Превращает dict с данными топика в sphinx'овый псевдо-XML
def format_document(document):
  return  '\n'.join(
    ['<document>'] +
    ['<%s>%s</%s>' % (k, document[k], k) for k in ['id', 'group', 'timestamp', 'title', 'body']] +
    ['</document>', '']
  )

# Выбирает и форматирует данные топика в dict
def topic_dict(topic):
  return {
    'id': topic.id,
    'group': topic.forum_id,
    'timestamp': int(mktime(topic.created.timetuple())),
    'title': escape(topic.subject.encode('utf-8')),
    'body': escape(text(topic).encode('utf-8')),
  }

for topic in Topic.objects.all():
  print format_document(topic_dict(topic))

API

Из Джанго к серверу Sphinx'а можно обращаться двумя способами: через django-sphinx или через включенный в поставку самого Sphinx'а общий питоновский API. Я попробовал оба, причем переключался с одного на другой и обратно раза два. Остановился на сфинксовом API. Почему не подошел django-sphinx определенно сказать не берусь :-). Видимо, на мой вкус он оказался недостаточно вылизанным. По идее он старается быть похожим на джанговский queryset, но в паре мест некрасиво лажается:

В итоге остановился на sphinxapi.py из поставки. Код вьюхи, которая его использует, очень прямолинейный и скучный, но чтобы не отходить от традиций приведу его здесь:

def search(request, slug):
  forum = get_object_or_404(Forum, slug=slug)
  try:
    from sphinxapi import SphinxClient, SPH_MATCH_EXTENDED, SPH_SORT_RELEVANCE
  except ImportError:
    return render_to_response(request, 'cicero/search_unavailable.html', {})
  try:
    page = int(request.GET.get('page', '1'))
    if page < 1:
      raise Http404
  except ValueError:
    raise Http404
  term = request.GET.get('term', '').encode('utf-8')
  if term:
    sphinx = SphinxClient()
    sphinx.SetServer(settings.SPHINX_SERVER, settings.SPHINX_PORT)
    sphinx.SetMatchMode(SPH_MATCH_EXTENDED)
    sphinx.SetSortMode(SPH_SORT_RELEVANCE)
    sphinx.SetFilter('gid', [forum.id])
    sphinx.SetLimits((page - 1) * settings.PAGINATE_BY, settings.PAGINATE_BY)
    results = sphinx.Query(term)
    pages = _page_count(results['total_found'])
    if pages > 0 and page > pages:
      raise Http404
    ids = [m['id'] for m in results['matches']]
    topics = ids and Topic.objects.filter(id__in=ids)
  else:
    topics, pages = None, None
  return render_to_response(request, 'cicero/search.html', {
    'page_id': 'search',
    'forum': forum,
    'topics': topics,
    'term': term,
    'has_next': page < pages,
    'has_previous': page > 1,
    'page': page,
    'pages': pages,
    'query_dict': request.GET,
  })

Впрочем с sphinxapi.py тоже не все было гладко. Я нашел там баг. Выражался он в том, что после поиска по некому слову сначала в одном форуме, потом в другом, а потом опять в первом, поиск начинал возвращать нулевые результаты. Причем после перезагрузки моего приложения баг пропадал, а затем возвращался снова. Я предположил, что где-то там сохраняется состояние предыдущих выборок, которое не должно сохраняться, и так оно, судя по всему, и есть. Вот начало кода класса SphinxClient:

class SphinxClient:
  _host = 'localhost'
  _port = 3312
  _offset = 0
  _limit = 20
  _mode = SPH_MATCH_ALL
  # и еще 12 параметров

  def __init__ (self):
    pass

То есть все то, что должно быть, кажется, полями экземпляров объектов, лежит не в экземплярах, а в классе и, следовательно, является общим для всех. Видимо, туда куда-то и попадают результаты предыдущих поисков. Решилась проблема использованием метода __init__ по назначению: я переписал назначение всех параметров туда:

class SphinxClient:
  def __init__ (self):
    self._host = 'localhost'
    self._port = 3312
    self._offset = 0
    self._limit = 20
    self._mode = SPH_MATCH_ALL
    # и еще 12 параметров

Андрею Аксенову. Я извиняюсь, что не оформил это патчем: очень лень было в багтракере регистрироваться :-). Может, поправите при случае?

Живой индекс

Sphinx'овый индекс — монолитный, в него нельзя добавить новый документ, а надо перестраивать с самого начала (что ни в коем случае не плохо, потому что из-за этого он очень быстрый, насколько я понимаю). Если индекс пересчитывать редко, то полезность поиска уменьшается, а пересчитывать часто — дорого. Для решения этой проблемы в документации рекомендуется завести два индекса: основной, который пресчитывается редко, и маленький дополнительный ("дельта"), в который попадают только новые статьи. Sphinx умеет прозрачно искать сразу по двум индексам.

Я так и сделал, причем для отделения новых топиков от старых получилось элегантно использовать уже существующую систему определения прочитанности. То есть я просто завел одного системного пользователя "cicero_search", который "прочитывает" все статьи при полной переиндексации, а его непрочитанные топики попадают в дельта-индекс. В коде это выглядит так:

cicero_search = Profile.objects.get(user__username='cicero_search')
if sys.argv[1] == 'unread':
  for topic in cicero_search.unread_topics():
    print format_document(topic_dict(topic))
elif sys.argv[1] == 'all':
  for topic in Topic.objects.all():
    print format_document(topic_dict(topic))
  cicero_search.add_read_articles(Article.objects.all())
  cicero_search.save()

Сейчас дельта-индекс пересчитывается раз в 10 минут, основной — раз в сутки.

Интерфейс

В большинстве форумов, которые я видел, интерфейс поиска упрятан за какие-нибудь ссылки-кнопки, причем упрятан хорошо! Наверное для форумов, где в десятке топиков идет вечный чат, это не самая нужная фича, но у меня — одна из самых главных. Поэтому строка поиска размещается на странице форума прямо в самом верху.

Надо будет еще ссылочку в сайдбары второстепенных страниц распихать, пока я это просто позабыл.

Впечатления и пожелания

В целом, все хорошо! Работает, ищет, все очень быстро (хотя при нынешних объемах это не показательно), русская морфология есть, релевантность вроде тоже вменяемая получается.

Но если помечтать, то у меня есть несколько пожеланий, в духе "каким я вижу идеальный поисковый сервер".

Комментарии: 44

  1. Светляк 40вт

    Я тоже уже наверное месяц назад прикрутил к своему блогу поиск на Sphynx, но в "продакшн" пока так и не выложил, и всё по той же самой банальной причине — никак не хватает времени собрать нормальный дебиановский пакет, а компилять это дело на хостинге мне не позволяет чувство прекрасного :)

  2. Давид Мзареулян

    Да, Сфинкс — штука очень приятная и перспективная. Но у меня два вопроса возникли по этому постингу: 1) неужели в Цицеро уже так много материалов, что потребовался дельта-индекс? и 2) какая скорость индексирования (время, байт/сек, док/сек) получается в Вашем случае? Интересно, насколько велик оверхед по сравнению с SQL-доступом.

  3. Иван Сагалаев

    неужели в Цицеро уже так много материалов, что потребовался дельта-индекс?

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

    какая скорость индексирования (время, байт/сек, док/сек) получается в Вашем случае

    Вот полная индексация (всего 182 документа, оказывается):

    total 182 docs, 612572 bytes
    total 0.671 sec, 913207.10 bytes/sec, 271.32 docs/sec
    

    Самый большой оверхед, я подозреваю, не в том, что это в XML конвертируется, а в том, что на каждый топик делается отдельный подзапрос его статей. Но пока меня все устраивает.

  4. Давид Мзареулян

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

    Мне кажется, тут имеет место антипаттерн «преждевременная оптимизация». Через пару лет или шах помрёт или… в общем, на действительно больших проектах не факт, что дельта — оптимальный алгоритм (от характера проекта зависит). А на небольших и средних скорость полной переиндексации сфинкса более чем достаточна. Он действительно крайне быстр. Должен быть…

    Но вот Ваши цифры мне как-то совсем не понравилсь. Может быть, конечно, влияет малое число документов, но вообще-то это песец. Вот так у меня индексируется реальный форум (20K небольших постингов):

    collected 21329 docs, 8.8 MB
    sorted 0.8 Mhits, 100.0% done
    total 21329 docs, 8826329 bytes
    total 1.715 sec, 5145977.50 bytes/sec, 12435.36 docs/sec
    

    А вот реальный СМИ-сайт (10К полноценных статей — видно, что и тут можно спокойно делать полный реиндекс раз в 10—20 минут без всякой дельты):

    collected 10898 docs, 80.3 MB
    sorted 5.4 Mhits, 100.0% done
    total 10898 docs, 80280154 bytes
    total 16.530 sec, 4856496.70 bytes/sec, 659.27 docs/sec
    

    Мне кажетя, если и оптимизировать, то где-то здесь, потому что разница в скорости слишком велика.

  5. Иван Сагалаев

    Я не вижу здесь преждевременной оптимизации, если честно. Из двух решений я выбрал то, которое в принципе масштабируется, и много времени это не отняло.

    А про скорость в документах в секунду — это скорее всего как раз та разница, которая возникает из-за того, что я делаю не один запрос, который выдает все документы, а по запросу на каждый. Очень похоже по порядку цифр, по крайней мере. Но еще раз повторюсь, меня это устраивает :-).

  6. Давид Мзареулян

    Мне это трудновато понять. Зачем в одном месте предусматривать масштабируемость, если система гарантированно заткнётся гораздо раньше и совершенно в другом месте?

  7. Иван Сагалаев

    А я не понимаю, почему эти вопросы вообще связаны :-). Скорость индексации как таковую можно будет еще пооптимизировать, буде это необходимо. Разделение же индекса на дельту и основу — это просто дешевый способ добиться того, чтобы переиндексацию можно было запускать чаще. А если полный индекс будет пересчитываться даже час-другой, его можно будет просто запускать реже, раз в неделю например.

    Давид, я наверное догадываюсь, что Вы считаете двойной индекс преждевременной оптимизацией, потому что оно кажется сложным эзотерическим решением. Но по мне оно — очень простое и очевидное, сделанное за 10 минут. А вот пытаться придумать какой-нибудь мудреный алгоритм, для поднятия скорости индексации — это как раз затраты времени на ту самую преждевременную оптимизацию.

  8. rushman

    Я для себя посмотрел и решил что лучше использовать Solr(http://lucene.apache.org/solr/) или что-то подобное.

    Подкупает открытый протокол на базе HTTP, то что поиск основан на Lucene (слышал о ней только хорошие отзывы), ну и к тому-же там прям из коробки есть возможность делать фасетную классификацию результатов.

  9. Юревич Юрий

    Не первый раз замечаю, как ты делаешь импорты внутри функций. Я стараюсь избегать таких конструкций. Дело, конечно, не в скорости. Просто когда импорты собраны в одном месте, сразу видны внешние зависимости модуля.

  10. Иван Сагалаев

    Да нет... Когда все импорты собраны в начале модуля, они создают зависимости. Например во view'хе, которую я тут в статье привел, очень явно видно, зачем импорт sphinxapi делается внутри: если Сфинкс не установлен, форумом все равно можно пользоваться, а при поиске юзеру напишется сообщение о том, что поиск недоступен.

    Я не считаю, что надо догматично держаться одной или другой стратегии. И у той, и у другой есть свои применения. В частности, джанговский views — это такой "мегамодуль", в котором собран целый уровень очень разной функциональности. Поэтому мне кажется неправильным выносить наверх локальные зависимости, нужные только одной довольно независимой части этой функциональности.

    В качестве мнемонического правила в таких мегамодулях я обычно придерживаюсь того, что выношу импорт наверх либо когда он встретился в двух локальных местах, либо когда это стандартный рантайм, который всегда есть (типа datetime или os).

  11. Traut

    как вариант - можно было довольно просто прикрутить lucene/solr-сервер. как минимум, там индекс гибкий. а связать с db можно и вручную

  12. bialix

    Да нет… Когда все импорты собраны в начале модуля, они создают зависимости. Например во view’хе, которую я тут в статье привел, очень явно видно, зачем импорт sphinxapi делается внутри: если Сфинкс не установлен, форумом все равно можно пользоваться, а при поиске юзеру напишется сообщение о том, что поиск недоступен.

    Пользуйте ленивый импорт.

  13. Франковский Богдан

    Тут есть интересное размышление на тему lazy import.

  14. Иван Сагалаев

    Пользуйте ленивый импорт.

    Хм... А зачем? Если импорт из локальной функции и проблему решает, и более явно передает намерения.

    Я, честно говоря, вообще не вижу смысла во что бы то ни стало выносить импорты наверх файла, нарушая инкапсуляцию — связь импорта с кодом, для которого он нужен.

  15. Франковский Богдан

    Травмы после Pascal'я и C наверно :D

  16. evilhare

    Иван, у меня такой вопрос. В чём преимущество прикручивания таких движков по сравнению с Google API или Yandex XML (кроме скорости индексации или она тут критична)? Просто и качество морфологии, например, у них выше и работ по приделыванию на час-два где-то.

  17. Иван Сагалаев

    Сторонние сервисы такого рода, мягко говоря, сильно ограничены по функциональности. Например у Яндекс.XML есть лимит в 1000 запросов в день, а Google, если я не ошибаюсь, то ли вообще закрыл свой SOAP-интерфейс к поиску, то ли сделал его платным. Опять-таки, ни тот, ни другой сервис не будут "ложиться костьми" для того, чтобы проиндексировать именно мой форум именно так, как мне надо. Другими словами — это очень половинчатое и ненадежное решение.

    А насчет двух часов... Я не могу сказать, что прикручивал Сфинкс очень долго. Не два часа, конечно, а два вечера, но поскольку для меня программирование — удовольствие, я не могу сказать, что как-то этим недоволен :-)

  18. evilhare

    Иван, спасибо!
    Да, у меня пока не набирается 1000 поисков в день, а SOAP-аккаунт я успел отхватить в своё время :)
    Про точность индексации согласен, мне пришлось посидеть над сочинением поискового запроса, выбирающего из проиндексированных страниц только те, которые нужны пользователю.
    Так что когда выйду за пределы допустимого в Гугле, то буду знать, что ставить на замену.

  19. bialix

    Я, честно говоря, вообще не вижу смысла во что бы то ни стало выносить импорты наверх файла, нарушая инкапсуляцию — связь импорта с кодом, для которого он нужен.

    Сказывается специфика web-программирования. Умолкаю.

  20. Maxime

    Помнится, “купила” меня в итоге фраза о том, что он дает большую релевантность в поиске точному
    совпадению введенной фразы, а не просто близко стоящим словам (или что-то в таком роде :-) ).

    Хотел бы я знать, что это значит, в смысле "большая релеватность точному совпадению введенной фразы" :)

    Скорость мерять на данных, целиком влезающих в память - ну это как-то не очень правильно, хороший форум это все-таки несколько сотен тысяч ниток, или даже несколько пар миллионов, если форум популярен. Тестировать стоит начинать на объемах, превышающих объем ОЗУ.

  21. KpoT

    Скажите, Иван, а вы пробовали использовать Xapian? В предыдущей статье про поиск вы грозились это сделать. Лично я попробовал его именно после вашей статьи, и нашёл весьма удобным инструментом!

    • Прекрасно связывается с Python'ом, имеет инкрементный индекс, т.е. базу не надо будет переиндексировать заново, и костылей, вроде дельта-индекса не потребуется. (Вообще считаю такие негибкие индексы, как у Sphinx очень некрасивым решением, годящимся лишь в узком круге задач.)
    • Кроме того, нет никаких проблем с параллельным использованием индекса и его пополнением. Документы сразу оказываются в базе по мере их индексации.
    • Можно разбивать данные по полям документа и искать по ним отдельно.
    • Можно указывать свои критерии релевантности, например, выдавать документы порядке, обратном порядку их включения в индекс, игнорируя релевантность содержания.
    • Поддерживается русский язык, скорость индексации весьма внушительная, не хуже, чем у Sphinx.
    • Весьма богатый язык запросов.

    Расскажите, чем он пришёлся не по вкусу? Сам я его применяю уже несколько месяцев, без проблем. Но вдруг какие-то грабли всё же есть... Cам я, поначалу, тоже хотел использовать Sphinx, и пока безмерно рад, что этого не сделал.

  22. Иван Сагалаев

    Хотел бы я знать, что это значит, в смысле "большая релеватность точному совпадению введенной фразы" :)

    Это значит, что если я введу слова "язык запросов", то документы, где эти слова написаны точно так и в том же порядке, будут гарантировано встречаться выше, чем те, где написано, например, "запросы на языке" или "запрос языка".

    Скажите, Иван, а вы пробовали использовать Xapian?

    Для Xapian, если я правильно понял, нет уже написанного сервера, а мне писать было лениво :-). А без отдельного сервера, как я понял после прошлых изысканий, поиск все таки не делается. Впрочем, все не высечено в камне, и возможно я и Xapian когда-нибудь попробую. Чисто по отзывам, что Sphinx, что Xapian, что Lucene — примерно одинаковы по качеству. Я решил таки уже выбрать что-то одно и попробовать руками.

  23. Andrew Aksyonoff

    если бы у сервера был не свой собственный (бинарный!) протокол обмена данными,

    Бинарный будет завсегда.
    Но понятно что можно прикрутить XML обертку в том числе внешнюю.

    XML-интерфейс индексатора все таки должен быть полнофункциональным

    Это скоро будет.

    свет клином не сошелся на двух СУБД.

    Оно далеко не хардкодом там ровно 2 СУБД поддерживает ;)
    Те. драйвер для очередного спец-источника данных в общем-то не шибкая
    проблема дописать.. даже и самостоятельно.

    Собственно и доступ в СУБД можно реализовать над XML-интерфейсом,

    Можно, но далеко не вегда не нужно.
    Потому что лишние ненужные оверхеды на создание и разбор XML.

  24. Andrew Aksyonoff

    в смысле “большая релеватность точному совпадению введенной фразы” :)

    http://sphinxsearch.com/doc.html#weighting

    Причем просьба понимать правильно.

    Ранжирование на основе LCS далеко НЕ панацея во-1х, слишком упрощенный подход во-2х,
    не сделана куча фокусов для дальнейшего улучшения ранжирования в-3х - все это известно.

    Но оно с ходу заметно лучше чем обычный BM25.
    И будет, таки я надеюсь, со временем улучшаться!

  25. Andrew Aksyonoff

    тоже хотел использовать Sphinx, и пока безмерно рад, что этого не сделал.

    :)

    Кроме отсутствия инкрементальных обновлений интересно есть какие-то showstoppers?

    В перечисленном списке их нет - все кроме обновлений Sphinx в общем-то тоже умеет.

  26. Иван Сагалаев

    свет клином не сошелся на двух СУБД.

    Оно далеко не хардкодом там ровно 2 СУБД поддерживает ;)
    Те. драйвер для очередного спец-источника данных в общем-то не шибкая
    проблема дописать.. даже и самостоятельно.

    Понимаю, что не захардкожено :-). Мой поинт в том, что сейчас для того, чтобы написать нативный драйвер, нужно написать кусок C++ кода и положить его в Sphinx и пересобрать его. Именно поэтому нынешний XML Pipe лучше: его может написать пользователь, а не ждать, пока разработчик сервера поиска поддержит разлюбимую СУБД пользователя или отревьюит патч пользователя.

  27. Andrew Aksyonoff

    Именно поэтому нынешний XML Pipe лучше:

    Переделанный (с поддержкой всех новых фич) будет лучше для среднего пользователя, спору нет.

  28. KpoT

    Про showstoppers Xapian:

    Кроме отсутствия инкрементальных обновлений интересно есть какие-то showstoppers?
    В перечисленном списке их нет - все кроме обновлений Sphinx в общем-то тоже умеет.

    Честно говоря, лениво сравнивать Sphinx и Nginx по фичам :) Я ведь никого особо не агитирую :) Тем более, Sphinx не применял, и сравнивать права не имею. Но инкрементный индекс, на мой взгляд, уже достаточно шикарная фича, чтобы только ради неё сделать выбор в пользу поддерживающего его поисковика. Вы можете содержать один, два, десять дельта-индексов, но рано или поздно придётся делать полную переиндексацию. На мой взгляд, это совершенно неприемлемо. Иван выбрал Sphinx за наличие сервера. Пусть так. А если сервер используется для индексации данных из нескольких источников? Гонять периодически ВСЕ ИХ ДОКУМЕНТЫ по сети в виде XML'а?! Как-то, гхм,... некрасиво.

    Следующее преимущество инкрементного индекса - простота поддержки. Никаких записей в cron, информацию можно добавлять и обновлять в тот же момент, как она поступила. И она сразу доступна ищущим.

    К слову, я не использовал Xapian напрямую, а сам написал сервер минут за 20-30, используя в качестве протокола обмена JSON. Вышло не так уж и сложно.

    Возможно, Sphinx ищет немного лучше. И в каких-то проектах это настолько заметно и критично, что является решающим фактором. Но поиск вообще вещь довольно приблизительная, и оценивать его качество, как вы понимаете, очень нелегко. Мне результаты, выдаваемые Xapian на русскоязычных документах, показались отличными (частенько приходится пользоваться).

  29. KpoT

    Просьба в предыдущем комментарии читать Nginx как Xapian :)

  30. Andrew Aksyonoff

    но рано или поздно придётся делать полную переиндексацию.

    А с любой инкрементальной структурой рано или поздно придется делать дефрагментацию - чтобы поиск не так жутко тормозил ;)

    Но в общем мысль ясна, спасибо - в вашем случае именно преимущества онлайн апдейтов заслонили все остальное.

  31. Maxime

    Хотел бы я знать, что это значит, в смысле “большая релеватность точному совпадению введенной >>фразы” :)

    Это значит, что если я введу слова “язык запросов”, то документы, где эти слова написаны точно так >и в том же порядке, будут гарантировано встречаться выше, чем те, где написано, например, “запросы >на языке” или “запрос языка”.

    Что-то это объяснение совсем все запутало... Вы можете привести пример поисковой машины, где это не так ?
    Я думал будет речь идти о "язык запросов" и "язык логических запросов".

  32. Sasha Bochkin

    А пострегсовский tsearch2 не был выбран как вариант по той причине, что это бы привязывало поиск по форуму к определенному движку? Или есть и другие весомые причины?

  33. Давид Мзареулян

    Но в общем мысль ясна, спасибо - в вашем случае именно преимущества онлайн апдейтов заслонили все остальное.

    Андрей, а Вы бы сами что про Xapian (по сравнению со Сфинксом) сказали? Вы же наверняка его смотрели тоже.

  34. Andrew Aksyonoff

    Андрей, а Вы бы сами что про Xapian (по сравнению со Сфинксом) сказали? Вы же наверняка его смотрели тоже.

    Я смотрел очень по диагонали, причем высматривал недостатки ;) С ходу высмотрел следующее:

    • ранжирование при помощи чистого BM25 (которое мне не нравится);
    • не заметил поддержки распределенного поиска;
    • не заметил поддержки group-by;
    • хуже поддержка фильтров.

    SQL индексатор на основе Perl как-то немного подозрителен (см. оверхеды). Скорость не сравнивал. В общем и целом, yet another BM25 library, так что ни малейшего желания срочно закрывать Sphinx не возникло.

  35. Макс Лапшин

    Я вот, глядя на твой цицеро, думаю, может сделать похожую штуку для рельс?

    У нас проблема такая: вставить в софтину на рельсах своё приложение оооочень сложно. Практически невозможно, потому что ребятам из 37signals это не нужно. Однако, всё равно, попытаться стоит. Меня в создании форума останавливает только одно: я сам рисовать не умею, а нужен нормальный дизайн.

  36. Иван Сагалаев

    Дизайн можно у комьюнити попросить. Когда форум будет работать. Зачем оно (комьюинити) иначе еще нужно, как не делиться друг с другом умениями :-)

  37. Макс Лапшин

    Ну может и так.

  38. hazeller

    Все бы хорошо, но у меня в форуме единица информации — целиком топик, а не отдельная статья. Получается, мне нужен запрос, который бы выдавал ID топика и весь его текст, то есть текст всех его статей. Я слишком плохо знаю SQL, чтобы составить такой запрос

    У меня тоже такая проблема возникла.
    Задача: Есть 2 таблички Threads(темы) и Topics(посты)
    Нас интересует табличка Topics:

    topic_id|thread_id |message |...
    1 |1 |тра та та |
    2 |1 |мы везём с собой кота|

    Логично искать не в каждом посте и во всей теме, т.е. во всех постах одной темы. Задача решилась подстановкой в конфиг sphinx такой вот выборки:

    SELECT thread_id, GROUP_CONCAT( message )
    FROM `forumTopics`
    GROUP BY Thr_Code
    

    т.е. в рез-те

    |1 |tratata мы везём с собой кота|

  39. Иван Сагалаев

    Спасибо за решение.

    Хотя, оно специфичное для MySQL, опять-таки...

  40. пользователь сгдс

    Интересно, а если к Сфинксу прикрутить небольшую программу паука, которая будет обходить заданные сайты, парсить оттуда текст, формировать ID на основе URL и какой-то системной информации и скармливать это сфинксу, вполне может получиться классический поисковичек. В кач-ве дополнительных полей имя сайта (для группировки). Со ссылочным ранжированием проблемы, паука надо научить считать ссылки (он их всё равно должен уметь парсить) и отдавать их Сфинксу, а тот в выдаче отдавать страницы не только релевантные, но и на которые больше ссылок.
    Глядишь через пару лет увидим полноценный Web-поисковик

  41. [...] заменяют стандартный поиск (полный список). Кстати, интересное обсуждение о выборе поисковика для Python [...]

  42. [...] в свое время описывал, как включал Sphinx на этом форуме. Там все еще довольно актуально, в частности вывод о [...]

  43. SphinxSE — это версия, функционирующая как движок хранения данных для MySQL (требует патча и перекомпиляции базы), Ultrasphinx — конфигуратор и клиент для Ruby (кроме присутствующего в дистрибутиве API), кроме этого есть плагины для многих известных CMS и блог-платформ, вики, которые заменяют стандартный поиск (полный список). Кстати, интересное обсуждение о выборе поисковика для Python веб-проекта.

  44. http://alec-c4.com

    Коллеги, а вам не приходилось при работе со сфинксом реализовывать контекстный поиск? Например чтобы для поста в форуме или блоге отображались сходные посты?

Добавить комментарий