Загадки «Сфинкса»
Сейчас много текста будет, напрягитесь.
«Сфинкс» — это довольно известный поисковый движок, разработанный Андреем Аксёновым. Время от времени мне приходилось использовать его в своих проектах и каждый раз качеством получившегося решения я был доволен, тем более, что за проходившее время он обрастал новыми интересными возможностями.
В первый раз сталкиваюсь с проектом, где использование «Сфинкса» возможно только с некоторым количеством костылей, которыми решение обрастает и меня всё меньше устраивает получившееся. Хочу описать проблемы, с которыми я столкнулся, возможно
«Сфинкс» хорош поиском по одной сущности, это, пожалуй всё. Богатство, описанное документации может создать обманчивое ощущение, что он может больше, но это не так. Моей ошибкой было решение использовать его в поиске по связанным сущностям. Это то, что «Сфинкс» умеет плохо. И хотя то, что получилось работает по скорости выше предыдущего решение, прокручивая в голове исходный код, я пла́чу мысленными кровавами слезами.
Так получилось, что искать мне нужно по наборам сущностей, связанных между собой. Получилось аж пять индексов. Объём данных не даёт надежды упихать всё в плоскую структуру — избыточность ужасает. Например, есть документы (Д) и резолюции к ним (Р), отношение один ко многим. Если попробовать положить эту структуру в одну таблицу, избыточность будет на уровне Д×Рср (Рср — резолюций на документ в среднем). Причём «Д» на уровне миллионов. И это только две сущности. Немаловажно, что «Д» и «Р» — сущности с целой кучей полей, в том числе полнотекстовых.
Выход есть. В поиске мы смотрим по каким сущностям надо искать, ищем по первой, берём оттуда найденные идентификаторы, подставляем во второй поисковый запрос вместе с критериями и так далее. Это костыль номер раз. Форма поиска устроена таким образом, что использование любого фильтра, как правило, ограничивает количество данных в выборке очень сильно, и всё равно это тысячи айдишников.
Второй костыль нужен, чтобы обойти принципиальное ограничение «Сфинкса» — у него есть параметр (указывается в конфиге), ограничивающий максимальное количество возвращаемых данных. Причём в миллионы (наш объём) его поставить нельзя — максимум в десятки тысяч, не рассчитан «Сфинкс» на большее, да и памяти не напасёшься. Всё бы ничего, но когда мы ищем пересечения сущностей (Д×Р), то, что нам вернул «Сфинкс» со своим лимитом, может и не иметь пересечений — они могут быть за горизонтом выдаваемых данных.
Костыль номер два я походя описывал — если мы обнаруживаем, что айдишники вернулись не все, то делаются ещё запросы, которые я назвал «докачивающими», делается тот же самый поисковый запрос, за исключением айдишников, которые уже попали. Работает, естественно, только с данными отсортироваными по ID.
Как только появились «докачивающие» запросы, то минус один выходной ушёл у меня на костыль номер три — я сделал сбор статистики запросов и оптимизацию порядка выполнения запросов. Вот как всё работает.
У нас, как я уже сказал, может быть от одного до пяти задействованных индексов, в зависимости от того что пользователь в форму введёт. В запрос к каждому следующему передаются идентификаторы из предыдущего. Как только один из запросов вернул пустоту, дальше можно не продолжать — пересечение с пустотой даёт пустоту.
Теперь следите за мыслью. Не знаю очевидно или нет, но логически всё равно в каком порядке будут опрашиваться индексы — результат будет тот же. Например, Р ∩ Д = Д ∩ Р. Зато если впереди поставить запросы, которые вернут меньше айдишников, следующим будет полегче. Скажем, на запрос пользователя у нас вернулось 80 тысяч документов и пять тысяч резолюций. Расточительнее сделать запрос к документам первым и подставить потом 80 тысяч айдишников во второй запрос, чем выбрать сначала пять тысяч резолюций, а потом передать их в запрос к документам.
Но как узнать какой запрос надо выполнить первым? Поможет сбор статистики.
Я рассуждал так. Поскольку у нас в поисковой форме все атрибуты запрашиваются с критерием «И» (например: год=2011 И организация=5), то чем больше разнообразных критериев запрошено, тем меньше объём выборки, значит надо как минимум запомнить какие атрибуты интересовали пользователя, тем более, что они
В итоге при каждом поиске пользователя я кладу его запрос в специальный стек, плюс указываю какие атрибуты в каком количестве он запрашивал. Эта информация может выглядеть
В офлайне (ночью, например) срабатывает скрипт, который запускает полученный запрос и смотрит сколько данных получается, если этот запрос выполнится первым (без переданных айдишников). Из информации об атрибутах делается хеш и к нему приписывается полученный результат, учитываются предыдущие результаты по тому же хешу и в другую таблицу записывается пара хеш и средняя оценка значений возвращаемых запросом такого рода.
В дальнейшем, когда пользователь будет искать, мой код смотрит в эту статистику, оценивает характер запроса по описанном алгоритму и сортирует запросы к индексу так, чтобы первыми стояли индексы, которые вероятно дадут меньше результатов.
Массовых испытаний ещё не было, но в тех частных случаях, которые я рассмотрел, ускорение бывает до двух раз (чаще всего, конечно, прирост не столь значителен или его нет). Больше всего выигрыш получается, если удаётся избавиться от «докачивающих» запросов.
Задача была интересной, а вот костыли не радуют. Либо надо научиться с ними жить, либо думать о переходе
Комментарии 56
Комментарий для Danil:
Избыточных данных будет,во-первых, ДxР×И₁×И₂×И₃, во-вторых, у Д порядок несколько миллионов, как я уже написал, а связь с «Р» — один ко многим, это значит, что «Р» в несколько раз больше, в худшем случае — на порядки. Даже индекс Д×Р будет не просто солидным, а огромным.
Комментарий для Евгения Степанищева:
Прислали ссылку, примерно на задорной шутке про «может только десятки тысяч документов» я сломался и не смог не откомментировать!!!
:) Ну мы типа поисковый движок.
Умеем поэтому именно поиск и еще всякое связанное с поиском.
Плохо?
Плохо???
Он этого вообще не умеет!
Ну те. нету в самом движке JOIN как концепции.
Вроде (вроде) и нигде более в поисковых движках нет, но может уже ошибаюсь.
Мне кажется, ошибка проектирования сразу как раз вот тут.
В куче полнотекстовых полей по всем сущностям.
По моему опыту, пользователям они типично таки НЕ нужны.
Даже если пользователи врут иначе.
Что мгновенно открывает ряд интересных возможностей.
Ну те. действительно нужны запросы вида «совпало слово ДУДОЧКА в документе И совпало слово КУВШИНЧИК в любой из резолюций к документу», так?
Оно не «принципиальное».
Оно штоп пользователи случайными запросами на 100M матчей себе ногу не отстреливали.
Извините, тупо неправда — причем на 3 (три) порядка.
кто-то спросил про [the] — защищает от такого настройками по умолчанию.
Поставить — можно.
Движок сам по себе — «рассчитан» вполне.
10M возвращаемых матчей — я тестировал, работает.
Вроде 32 байта на матч в худшем случае — или даже меньше, те. до 320 MB на запрос.
Там есть некий глупый слив производительности в этом случае, не очень большой — но работает.
Ну те. реально желающим потратить до 320 MB памяти и некоторое количество CPU на запрос, возвращающий 10 миллионов объектов в приложение, Сфинкс такую возможность — вполне предоставляет.
А тех, кто не хочет случайно просрать в никуда 30x320 = 10 GB памяти сервера, которого
…
Тут у меня возрвался мозг :(
:-)
Кусок запроса приведен про атрибуты, причем тут вообще полнотекстовый поиск…
В общем и целом, описание задачи крайне неполное.
Но из обрывков мне кажется (кажется), что тупо неправильно спроектированы индексы и запросы.
Навскидку, JOIN результатов поисков в разных индексах тут вряд ли нужен.
Нужна ловкая денормализация, возможно, частичная (ходовых атрибутов, например).
Нужны фокусы про оптимизацию смешанных атрибутивных и полнотекстовых запросов.
Поиски с ограничением по результату другого поиска, в принципе, уже можно сделать и в движке.
Но случай дико нишевой, плюс типично обходится легким перепроектированием.
Ну и эта, общая фрустрация от изобретенных костылей понятна, конечно.
Непонятно только, зачем при этом ругаться и, хм, писать неправду про моменты, которые как раз давно и отлично работают.
У нас натурально не хватает ряда нужных и полезных штук. Не сделаны, пока еще.
Но якобы невозможность вынуть 100K матчей из движка это, хм, мягко говоря, ни разу не одна из них
Комментарий для Danil:
Эээ. Там естьгде-то 3 тонкости, но все они именно с размером индекса как раз не связаны. Да и вот именно поиск (матчинг, ранжирование, итп) всегда работает одинаково, это вчистую сортировка найденного отъедает (или не отъедает) лишнее время.
Комментарий для Андрей Аксенов:
Ну, Андрей, я Сфинкс и не ругаю, вполне себе осознаю, что выбрал для решения задачи не тот инструмент, который не умеет то, что мне нужно.
И, да, увы, специфика документооборота (а я именно им занимаюсь), что поиск может быть и «ДУДОЧКА в документе И совпало слово КУВШИНЧИК в любой из резолюций к документу», просто потому что документ надо найти, а пользователи плохо ориентируются в этим миллионах — в мозгу столько не поместить. Я знаю случай (не единичный), когда весь отдел просматривал 15 тысяч документов, чтобы найти нужный. Могут быть любые поисковые запросы, да.
Про ограничение я, вероятно, не совсем верно выразился. Движок рассчитан, но с оговоркой — он всё делает в памяти и не умеет на диске. А на миллионы, умноженные на миллионы памяти не хватит.
В Apache Solr, судя по описаю есть.
Андрей, не стоит в бутылку лезть, у вас хороший продукт.
Только постоянно рукой заходить на страницу и проверять новые?
Комментарий для Андрей Аксенов:
Ещё пара ответов на некоторые вопросы.
В приложение нам столько не нужно, но 100—200 тысяч — бывает необходимо, чтобы подставить в следующий запрос к следующему индексу.
Если я напишу обстоятельно из чего состоят индексы, у меня тут будет простыня на несколько экранов :)
Увы, всевозможные фокусы мы уже выполнили.
Комментарий для Андрей Аксенов:
Поe-mail нет, но если залогиниться через OpenID, можно получить персональный RSS-поток с комментариями (это у меня такая принципиальная позиция была пара лет назад, но видимо надо переделать на простую подписку по e-mail'у).
Ххха, инструмент на предметку влобно (влобно) не ложится однозначно, кто бспорил-то?
Но по существу — мне кажется (кажется), что даже этот инструмент таки можно приспособить.
Приделать костыли поудобнее. Или даже взять и перепроектироваться без костылей.
Может, ошибочно кажется, но по имеющейся скудной информации вот так.
А по форме — тональность ряда утверждений на фоне фактических ошибок в других вызывают…
Легкое удивление.
Понятно.
Порядки размеров какие: документы большие, резолюции мелкие?
В любом случае, для случая ДУДОЧКА И КУВШИНЧИК денормализация таки работает.
Нехитрая, все резолюции свалить в 1 текстовое поле документа.
OMFG.
Я совершенно не понимаю ни откуда взялось «все в памяти», ни про «миллионы на миллионы», ну ладно.
Угу, нашел уже тоже.
:-)
Прогресс не стоит на месте, действительно, добавили около года назад.
Ну, прикольно!
Когда почитаем тут, как работает?!
?
Комментарий для Андрей Аксенов:
Легко объяснимо, я не ставил целью рассказать задачу от и до, этовсё-таки персональный блог, а не книга, тут большей частью обрывки мыслей.
Если имеется ввиду текст, то да, дело так и обстоит. Но атрибутов помимо текста хватает. Кроме того, у документа несколько текстовых полей разной природы.
Невозможно. У резолюций свои атрибуты есть. Задача сложнее чем кажется.
какой-нибудь комплексный запрос.
Я сейчас открою поисковую форму… секунду… и придумаю
«Документ, созданный в 2011 или 2012 году, зарегистрированный под номером, в котором встречается „Д08“ в период между 15.09.2011 и 15.03.2012 в организации №5, в тексте которого есть слово „Бугульма“, а в кратком описании — „роддом“, к которому есть сопроводительное письмо, зарегистрированное пользователем №133231, без куратора, к которому есть утверждённая резолюция за авторством пользователя №13213, подписанная ЭЦП».
Ну, например, так.
Комментарий для Андрей Аксенов:
Ну, я не отрицаю, что могу не понимать откуда взялось ограничение на результат, но как я понял по доке и сегодняшней переписке, это чтобы оно всю память не съело. Если съест, то что дальше будет? База (тот же Оракл) некоторые операции проводит на диске, Сфинкс, насколько я понимаю — в памяти, пользователей у меня не один, а десятки тысяч, что будет если каждому понадобится запрос, где выберетсясотня-другая тысяч документов? Вот это место я не понимаю.
Не знаю пока. :)
всё-таки, а то я уже сомневаться начал, правильно ли написал.
Про бутылку — я же помню, что ты очень экспрессивный товарищ :) По выступлениям помню. А уж когда автору обидно за свой продукт, любой полезет в бутылку, что ж я не понимаю что ли?
P.S. Ничего, что на «ты»? Когда мы переписывались во времена моей работы в «Яндексе», были на «ты».
P.P.S. Кстати, твоя фамилия Аксенов или Аксёнов
Порядки такие.
У документа порядка 50 атрибутов, плюс 4 текстовых поля (одно большое, три мелкие), у сопроводительного письма — 7, плюс одно текстовое, у резолюции — 26 атрибутов, плюс одно текстовое поле, у отметки об исполнении — 9 полей, плюс одно текстовое поле.
Да вообще без проблем обязано работать.
Увы, не верю, много всякого в посте не стыкуется.
как-то так, ну и это я молчу про нехитрые варианты доработки собственно движка.
Денормализация (хоть частичная) явно возможна и должна работать для немалой части запросов. «Докачивающие» запросы из коробки на объеме 100к просто не нужны, sanity check в конфиге на значение max_matches сейчас 10M и это именно sanity check. Индексировать значения фильтров, похоже, никто не пробовал. «Статистика» работать вообще не должна, тк. от перемены мест индексов ценник на поиск ключевиков и фильтрацию на стороне движка не меняется никак, тормозить может только приложение (либо API, если скриптовый язык).
Навскидку
FUD везде FUD и ошибки везде ошибки, в блоге их написать, в книге или камнем на стене выцарапать.
Задача наверняка сложнее, а в аболютную невозможность денормализации все равно не верю.
«Сложный» пример запроса транслируется в
Дефолт max_matches=1K и ограничение 10M сверху для того, чтобы не давать просто так брать и отжирать 10x10Mx32 = 3.2 GB памяти впорожняк. Еще раз: чтобы при 10 параллельных запросах помешать просрать 3.2 GB памяти персонажам, которые, например, путают max_matches (ограничение размер result set) с максимальным размером индекса, который можно обыскать (никак не ограничен) и пытаются
10K rps на поиск есть у Гугла, Твиттера и еще горстки компаний, у вас нету и не будет никогда. Запрос на 100K документов без осложнений отожрет 3.2 MB на клиента, по 32 байта на матч (найденный документ), те. ~100 MB при 30 workers. Каждый раз, как ты путаешь общее число аккаунтов в системе и rps, господь убивает котенка.
Шоу на выступлениях, комментарии тут, «обидно за продукт» и прыжки в бутылку это 5 (именно 5) разных, никак не пересекающихся явлений, причем идиоматической бутылки почитай не бывает. Легкое удивление (см. «откуда они это берут?!»), легкое удивление, русским
Аксёнов.
Комментарий для Евгения Степанищева:
Я правильно понял принцип что, до тех пор пока не наберётся критическое значение статистики, то поиск пользователя по запросу которого нет в статистике будет долгим. Сколько бы раз сегодня он не делал запрос, а вот уже завтра -- ему будет искаться быстрее?
Совсем не понимаю как выглядит такой запрос.
Если запускать лопатилку только по ночам — да.
Просто же всё.
Условно, простой запрос с айдишниками:
SELECT document_id FROM cards WHERE org_id=5 AND year IN(2010,2012) AND document_id IN (32312,32145,56456,4342…)
Запрос без айдишников:
SELECT document_id FROM cards WHERE org_id=5 AND year IN(2010,2012)
Я
А зачем вообще поисковый движок?
Почему нельзя искать напрямую в БД? Скорость проседает? Какая БД?
База Оракл. Причины две:
1) более сложный продукт по определению не может работать быстрее узкоспециализированного и простого, только если автор более простого не дебил (Аксёнов не дебил). Ну да, скорость проседает.
2) у Оракла есть полнотекстовый поиск, но полностью отсутствуют морфология, язык запросов и формулы релевантности.
Комментарий для Андрей Аксенов:
А, вот где камень преткновения. Я не думаю о денормализации только для части запросов, у меня задача — ускорить поиск вообще. Но даже если рассмотреть верхнюю часть запросов, то на первом месте стоит поиск по номеру (уже денормализовано всё, хранится он сильно сложнее), а потом идёт очень разномастная масса запросов, у которых второе место выделить тяжело. Думаю, можно попытаться оценку по времени построить и оптимизировать просто то, что дольше (но для этого надо запускать новый поиск в продакшн и мониторить, статистика для старого поиска тут не поможет, он иначе сделан внутри).
Не думаю, что нам стоит разбирать частности, разбор что какие данные хранит и каков их объём займёт не один час, а без этого ты будешь делать ошибки оценки, подобные этой:
Тут найдётся очень много, это слабое ограничение.
(всё-таки фича новая, вряд ли там код вылизан до идеала).
Давай я лучше спрошу о вещах, которые меня сильно волнуют.
1) ты посоветовал использовать JSON, тем не менее, он есть только в бете. Ставить бету в продакшн я не буду. В этой связи два вопроса — скоро ли релиз? Сильно ли деградирует по скорости поиск, если использовать JSON
2) из объяснения про память я понял, что если 10 клиентов запустили десять запросов, где выпало 10 миллионов результатов для выдачи в клиент, то это сожрёт 10×10M×32 = 2,98ГиБ. Правильно ли я понимаю, что «Сфинкс» на любой запрос теперь будет выделять под 320 мегабайт, вне зависимости от того, понадобятся они или нет (только если я ему в OPTIONS не уменьшу max_matches, конечно)?
3) и правильно ли я понял, что если памяти хватает (система не ушла в своп), то от размера max_matches производительность «Сфикса» не деградирует на отметке в десяток тысяч, потому что мне показалось, что в доке между строк написано иное: http://sphinxsearch.com/docs/archives/1.10 … tches.html. Я имею ввиду фразу
Конечно, там дальше речь идёт исключительно о RAM, новначале-то ещё и CPU упоминается, про который дальше молчок.
Да, второй пункт решает.
Я бы посмотрел в сторону 25 попарных индексов, ну и апачевского чуда.
Все же делать оболочку над поиском- решение стратегически неверное — нету простоты.
Комментарий для alxt.moikrug.ru:
А не 25 попарных индексов и не нужно, проблемы возникают с первой выборкой, как правило. Именно первый запрос даёт много айдишников, остальные редко приходится докачивать.
Вопрос ещё как «Сфинкс» поведёт себя под той же загрузкой, которую держит «Оракл». Нормального нагрузочного тестирования ещё не было, простые тесты показывают, что «Сфинкс» (вроде) лучше держится, но посмотрим.
Можно и еще 10 тройных попробовать сделать.
Так же мы вчера наваяли вариант когда атрибут держатся в денормализованных таблицах «Оракла», а полнотекстовый делается «Сфинксом» (тут нам на max_matches плевать, первых несколько тысяч ответов с сортировкой по релевантности хватит). Сегодня потестируем.
1. Должно чаще хватать одного индекса.
2. Выборка будет много меньше.
Кстати, если помещать индексы на отдельных компах, то можно запускать несколько поисков и отбирать минимальный результат …
Андрей, если ты тут ещё появишься, вопрос технического плана:
4) max_matches в том числе потому появился, что «Сфинкс» не умеет кидать в клиент небуферизированный ответ?
Комментарий для alxt.moikrug.ru:
Кажется выигрыш от использовании попарных индексов перекроет вред от потери в скорости переиндексации (сейчас на нашей неполной тестовой базе переиндексация день занимает, в случае, если мыгде-то ошиблись, у нас нет возможности остановить продакшн на несколько дней, чтобы поправить ошибку и переиндексировать).
Есть такой вариант, но это костыль, да ещё и дорогой костыль.
Комментарий для Евгения Степанищева:
JOIN в Solr отнюдь не аналог sql JOIN. В терминах sql это скорее подзапрос. То бишь по сути те же самые костыли что сделали вы, но с очень серьезными ограничениями — нельзя вернуть поля из 'from', нельзя искать по 'to'(разьве что фильтрами) и постоянный score для всех результатов.
Это уже интересно! Подзапрос — это тоже неплохо, по крайней мере оногде-то у себя в кишках это передаёт, мне не придётся туда-сюда гонять данные. Я вот это место не понял:
from и to в синтаксисе solr это что с чем джойнится.
1. Поля из сущностей которые во from вы вернуть в результате не можете. Только те сущности которые в to. То бишь если вы делаете join from документы to резолюции то на выходе у вас только резолюции, а не документы с резолюциями вместе.
2. Поиск только по from. Аналогично примеру выше искать вы можете только в документах, но не в документах и резолюциях одновременно. Но вы можете наложить фильтр на результат (резолюции).
3. Результаты после join не ранжированы. Вообще. Score для всех результатов равен 1. Сортировка в этом случает будет по дате попадания в индекс, то бишь кто раньше проиндексирован тот и выше.
Комментарий для artemp.pip.verisignlabs.com:
Мне, по сути, только ID документов нужны, в резолюциях они указаны.
Звучит немного туманно. Что такое фильтр на результат, чем он отличается от поиска?
Т.е. в случае, если мы ищем по тексту, релевантность идёт лесом. Печально.
Комментарий для Евгения Степанищева:
Значит вам повезло.
Технически это такой же поисковый запрос. Но фильтр может лишь ограничить исходную выборку, но не расширить её. То бишь для случая «дудочка в документах И кувшинка в резолюциях» фильтр применим, а для «дудочка в документах ИЛИ кувшинка в резолюциях» очевидно нет. Ну и фильтры не влияют на score, но с учетом следующего пункта в данном случае это не имеет значения.
Именно.
Разбей задачу фильтрации и поиска.
Фильтруй в оракле, ищи в сфинксе с уже более уточненными параметрами и упрощенным запросом.
Комментарий для Евгения Степанищева:
Кстати благодаря этой же особенности существует хитрость позволяющая в некоторых случаях обойти проблему constant score. Join можно использовать в фильтре вместо запроса.
Вот пример из документации solr:
Find all products matching ipod (sorted by score) and filter that by the set of products produced by joining manufacturers named «Belkin» or «Apple»
q=ipod&fq={!join from=id to=manu_id_s}compName_s:(Belkin Apple)
Комментарий для Евгения Степанищева:
Я подумал что запрос без _всех_ айдишников, а не только тех что в IN () :)
Дык разные категории запросов и ускорять надо
Определения «совсем чуть» vs «очень много» итп у нас наверняка расходятся
Теги beta либо release всегда довольно условны, есть желание от них
Фильтрация по WHERE json.key1=123 очевидно медленнее, чем по WHERE key1=123, но только фильтрация (поиск, ранжирование, сортировка итп не меняются ведь никак). Стало интересно, сделал тестовый запрос, 170K полнотекстовых матчей, крохотные JSON атрибуты вида {"p":1112547810,"c":1065929}. Получилось 0.055 sec WHERE channel_id=1065929 с обычными атрибутами и 0.063 sec WHERE j.c=1065929, фильтрация согласно SHOW PROFILE жрет 0.012 sec и 0.021 sec соответственно.
Буфер размером в max_matches сейчас аллоцируется сразу, поэтому при 10M и при 10 параллельных поисках сразу минус 3.2 GB, даже если там по 1 документу в итоге найдется. Еще этот буфер сразу обнуляется, что при 10K и даже 100K пофиг, а при 10M важно. Это технически возможно изжить и заоптимизировать, сделать буфер сделать динамическим. Мы даже начинали, но
Запросы с чистым атрибутивным поиском, которые ты регулярно
Переиндексация длиной в день это несколько терабайт данных или это dict=crc и включенные подстроки? Во втором случае dict=keywords и переиндексация будет занимать, ориентировочно,
Если все то, что описано artemp верно, то это у Solr ни разу не полноценный JOIN, а настолько херовенькое пересечение, что реализовать механизм поудобнее (без глупых ограничений п.2 и п.3) мы можем совсем нетяжело. Тупо реализовать SET local_var:=(SELECT id FROM …), плюс возможность использовать такой local_var в фильтре для последующих запросов в текщуей сессии, и всех дел.
Комментарий для Андрей Аксенов:
Будешь ли ты на 404?
Скажи, если я выбираю, условно
SELECT document_id FROM document ORDER BY document_id, то отсортированы будут все данные или только те, которые лезут в max_matches?
Комментарий для Андрей Аксенов:
Не подойдёт такое решение — организаций тысячи и это число быстро растёт. Каждый раз для новой организации перестраивать полностью индекс?
Запрос SELECT document_id FROM document ORDER BY document_id OPTION max_matches=1234 создаст приоритетную очередь размером 1234 элемента по 32 байта на элемент, просканирует все 10050011 строк индекса document (ну те. пробежится по лежащему в оперативке содержимому document.spa), выберет
Индекс перестраивать вообще незачем, если у организаций не меняются постоянно org_id, откуда ты это взял?! Запись id=123, orgid=5, name="ООО Ромашка", xkeywords="_orgid5" можно найти перебором 10050011 строк по условию WHERE orgid=5, а можно чтением списка только нужных записей по условию WHERE MATCH('_orgid5'). В этом месте не удержусь от подколки про «попробовали все фокусы»; ага, угу, конечно, наверняка!!!
Комментарий для Андрей Аксенов:
Ффух, значит работает как и думал. Хорошо.
Я просто не сообразил чем «поиск» отличается от «фильтрации».
Э, товарищ, твои костыли детские костылёнки по сравнению с нашими ;) Посмотри как я придумал упаковывать текст для разных организаций:
ORGID5 тут текст ENDID5 ORGID6 тут другой текст ENDID6
а потом поиск: ORGID5 >> текст >> ENDID5
у нас даже такой способ используется.
Э, ну везде перед этим ты довольно методично и не раз приводишь примеры про WHERE orgid=5, а вовсе не WHERE MATCH('_orgid5'), плюс странноватые ламентации про max_matches=10K. Это все в целом как бы намекает, поэтому я
Способ с BEFORE (ну то есть a>>b) прикольный. Еще можно [ZONE:orgid5 (текст)], вроде бы в этом случае ограничений на [текст] меньше. Навскидку, можно нарваться на беду со скоростью, если есть частотные словами в части [текст]. Синтаксически для избавления от такой упаковки оптимально уметь, условно говоря, свой набор полей для каждого документа, Solr как раз вроде умеет. Насколько эффективно оно внутри у них устроено и исполняется, впрочем, не знаю. C точки зрения производительности клевее всего сработает фокус с предобработкой индексируемых данных и запросами типа [_orgid5_дудочка _orgid5_кувшинчик]. Тоже все пробовали? ;)
Комментарий для Андрей Аксенов:
Такое не пробовали — слов многовато, страшновато применять. Явсё-таки смотрю в сторону JSON, раз уж ты говоришь, что он стабильный, но вот что смущает.
где-то снаружи должны быть, то как мне найти документ, у которого есть резолюция, созданная пользователем №1 в организации №2? Сфинкс не умеет же массивы просматривать?
Если я засуну все резолюции в структуру вида
[ { поля резолюции1 }, [ { поля резолюции2 }, … ] (понятно, что текстовые поля
У меня тут слюньки потекли на твою фразу, что можно было бы реализовать SET local_var:=(SELECT id FROM …). Насколько вероятно, что ты или
Поддержка JSON в транке полная (те. можно сохранить любой объект), довольно прилично оттестирована, более того, даже
Синтаксиса для просмотра массивов пока нету, обсуждали варианты на будущее буквально сегодня. Склоняюсь к питоновскому, те. нечто вроде SELECT * FROM myindex WHERE ANY(x.uid=1 AND x.orgid=2 FOR x IN jsoncol)
Кроме SET local_var нам «самим по себе» еще много чего куда более насущного есть запрограммировать. Однако можем попробовать (попробовать) сделать вот что. Я попробую очень быстро нахакать прототип, отдам снапшот тебе потестировать, и если (если) выйдет приятно по функционалу и производительности, обсудим коммерческую доводку до ума. Если такое интересно, напиши в скайп, чуть обсудим технические детали.
Комментарий для Андрей Аксенов:
Я ж не владелец бизнеса, попробую предложить.
Комментарий для Андрей Аксенов:
Мне кажется логичным рассматривать такой массив как таблицу и делать это синтаксисом подзапросов, но кажется пайтонячий будет просто короче.
Это не Пайтон, кстати,
Пайтон вот:
В
C:\Temp>cat 1.py
a = [1,3,5,7]
print any(x==1 for x in a)
print any(x==10 for x in a)
C:\Temp>python 1.py
True
False
Комментарий для Андрей Аксенов:
Сейчас поем, вылезу.
Да, но они работаютпо-разному вообще. На выходе будут массивы разной длины. Мой вариант — фильтрация, твой — итерация по всему.
Так мне и не нужны массивы. Мне нужны проверки!
Погоди, ты кажется не понимаешь в чём выгода.
Такое: [x for x in [1,0,0,0,0,0,0,0,0,10] if x]
Даст два элемента: [1, 10]
А такое: [x != 0 for x in [1,0,0,0,0,0,0,0,0,10]]
Кучу: [True, False, False, False, False, False, False, False, False, True]
Мне кажется, что первое выгоднее, особенно, если массивы большие.
Причём, если с True и False ничего полезного не сделаешь, то со значениями можно:
max(x for x in [1,0,0,0,0,0,0,0,0,10] if x)
Выдаст 10
Причем тут вообще детали реализации any() внутри питоновского рантайма? Я ж не собираюсь питон встраивать, я собираюсь тупо синтаксис позаимствовать. Этот пока выглядит наиболее внятным.
Да, я понимаю :) просто хочется выжать из этого синтаксиса как можно больше :)