Після написання цієї відповіді я, мабуть, ставлю це питання як "занадто широке" - ми можемо віками говорити про різні стратегії, врешті-решт, для ваших даних доведеться виконувати орієнтир.
Кожен тег може бути ефективно представлений цілим числом. Кожна організація має набір тегів. Вибір правильної реалізації набору важливий - можливі як B-дерева, так і відсортовані масиви. За допомогою цього набору ми будемо робити лише тести на членство. Оскільки обидві структури роблять це в O (log t) (з t тегами на сутність), я вважаю за краще масиви через їх більш щільне представлення.
Тепер ми можемо фільтрувати всі сутності в операції O (n · log t · p) , де p - середня довжина шляху в дереві рішення предикатів. Це дерево рішень можна замовити таким чином, щоб швидко було прийнято рішення. Без статистичних даних можна лише визначити загальну субекспресію.
Порядок пошуку суб’єктів не дуже важливий. З іншого боку, може бути вигідним сортувати його таким чином, щоб сутності, що мають індекси 0
для i
всіх, мали певний тег, а решта - ні. Це зменшує n під час пошуку цього конкретного тегу (у дереві рішень це має бути перший тест). Це може бути розширено до декількох рівнів, але це ускладнює речі та займає O (2 k ) пам'ять з kрівні. При декількох рівнях слід спершу визначити теги з найбільшим коефіцієнтом посилення, де коефіцієнт посилення - це кількість об'єктів, які не повинні шукати в рази більше від ймовірності їх відкидання. Коефіцієнт посилення стає максимальним за 50:50 шансів або коли 50% суб'єктів мають цей специфічний тег. Це дозволить вам оптимізувати, навіть якщо шаблони доступу не відомі.
Ви також можете створити набори, які індексують сутності за кожним використовуваним тегом - один набір із усіма сутностями для T1
, наступний для T2
. Очевидна (просторова і часова) оптимізація - це зупинитись, коли набір містить більше половини всіх елементів, і зберегти ті елементи, у яких немає цього тегу, - таким чином, побудова індексів для всіх тегів займе менше ½ · n · t
місця ( t тегів усього). Зауважте, що збереження додаткових наборів може ускладнити інші оптимізації. Знову я б (сортував) масиви для наборів.
Якщо ви також представляєте ваші сутності через цілий діапазон, ви можете стиснути простір, який використовується для наборів індексів, лише зберігаючи початковий і кінцевий член безперервного діапазону. Це означає, що це може бути зроблено з високим бітом, щоб вказати, чи є запис обмеженим діапазоном або регулярним входом.
Якщо тепер у нас є набори індексів (і, отже, статистика щодо тегів), ми можемо оптимізувати наші предикати так, щоб навряд чи властивості були перевірені спочатку (стратегія відмови). Це означає, що якщо T1
загальний і T2
рідкісний, то предикат T1 & T2
слід оцінювати шляхом ітерації через усі T2
записи набору індексів та тестування кожного елемента для T1
.
Якщо ми використовуємо відсортовані масиви для реалізації наборів індексів, то багато етапів оцінки можуть бути реалізовані як операції злиття. T1 & T2
означає, що ми беремо T1
і T2
списки, виділяємо цільовий масив розміром більших входів і виконуємо наступний алгоритм, поки обидва входи не будуть порожніми: Якщо T1[0] < T2[0]
, тоді T1++
(відкиньте голову). Якщо T1[0] > T2[0]
тоді T2++
. Якщо обидва головки рівні, то скопіюйте цей номер в цільовому масив, і збільшують всі три покажчика ( T1
, T2
, цільові). Якщо присудок є T1 | T2
, то жодні елементи не відкидаються, а менші копіюються. Предикат форми T1 & ¬T2
також може бути реалізований з використанням стратегії злиття, але ¬T1
і T1 | ¬T2
не може.
Це слід враховувати при впорядкуванні дерева рішень про предикати: Доповнення повинні відбуватися або на RHS &
, або в кінці, коли визначається остаточне підрахунок і фактичні елементи не потрібно дивитись.
Без використання наборів індексів кожен потік може фільтрувати свою частину сутностей і повертати кількість елементів, що відповідають предикату, які можна підсумувати. При використанні наборів індексів, то кожному потоку буде призначено по одному вузлу в дереві рішення. Він займає два вхідні потоки, які відповідають упорядкованому набору, і повертає об'єднаний потік. Зауважте, що кожен вузол у дереві рішень має відповідний набір, який представляє всі сутності, які виконують цей підвираз, і що через впорядкування наборів не потрібно знати весь набір одразу для їх об’єднання. .
Різні стратегії, такі як об'єднання індексованих наборів або фільтрація через список сутностей, можуть певною мірою поєднуватись. Фільтрування має дуже передбачувані показники. Якщо запит дуже специфічний, так що використання наборів індексів різко скорочує простір пошуку, то операції з об'єднання можуть бути кращими. Важливо зауважити, що об'єднання багатьох великих наборів вводу може призвести до набагато гірших результатів, ніж пошук з грубою силою. Дуже оптимізований алгоритм вибере відповідну стратегію на основі вхідного розміру, структури запиту та статистичних показників.
В сторону кешування часткових результатів може бути корисним, якщо очікується, що подібні запити будуть запущені в майбутньому, навіть якщо вони не прискорюють початковий запуск.
T1
та ж посилання на об'єкт дляE1
,E2
і т.д.?