> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pubrio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Обзор фильтров

> Как работают фильтры поиска Pubrio — единый движок фильтров, семантика AND/OR и когда что использовать.

Эндпоинты поиска Pubrio (`/companies/search`, `/people/search`, `/companies/advertisements/search`) используют единый движок фильтров. Вы составляете тело запроса один раз, и одни и те же правила действуют на всех эндпоинтах — включая способ комбинирования мультизначных фильтров, сопоставление локаций и переопределение оператора по умолчанию с помощью `filter_conditions`.

## Зачем единый движок фильтров?

<CardGroup cols={2}>
  <Card title="Одна схема, три эндпоинта" icon="arrows-rotate">
    Фильтры на уровне компании, такие как `technologies`, `verticals` и `founded_dates`, работают одинаково на `/companies/search`, `/people/search` и внутри `company_filters` в мониторах — вы изучаете их один раз.
  </Card>

  <Card title="AND/OR для каждого фильтра" icon="code-merge">
    По умолчанию используется OR (совпадает любое). Переведите отдельные фильтры в AND (совпадают все), добавив одну запись в `filter_conditions` — не затрагивая остальную часть тела запроса.
  </Card>

  <Card title="Нативные операторы Postgres" icon="database">
    Фильтры-массивы компилируются в нативные операторы Postgres — `&&` (пересечение) для OR, `@>` (содержит) для AND. Индексируемо, без постфильтрации на стороне приложения.
  </Card>

  <Card title="Те же фильтры в мониторах" icon="bell">
    Блок `company_filters` в [Monitors](/ru/developer-guides/introduction) принимает ту же форму, поэтому рабочий payload поиска также является рабочим payload монитора.
  </Card>
</CardGroup>

***

## Анатомия поискового запроса

Каждый поисковый запрос строится из трёх слоёв в одном JSON-теле:

| Слой                      | Где находится                                                                               | Примеры                                                                        |
| ------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Фильтры по людям          | ключи верхнего уровня                                                                       | `people_titles`, `management_levels`, `departments`, `people_locations`        |
| Фильтры по компаниям      | вложены в `company_filters: {...}` (рекомендуется) — также принимаются на верхнем уровне    | `technologies`, `verticals`, `founded_dates`, `employees`, `company_locations` |
| Переопределения оператора | массив `filter_conditions` (внутри `company_filters`, если переопределяются ключи компании) | `[{ "key": "technologies", "operator": "and" }]`                               |

Минимальный запрос `/people/search`, использующий все три слоя:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.pubrio.com/people/search \
    -H "Content-Type: application/json" \
    -H "pubrio-api-key: YOUR_API_KEY" \
    -d '{
      "people_titles": ["VP of Engineering", "CTO"],
      "company_filters": {
        "technologies": ["Kubernetes", "Docker"],
        "is_enable_similarity_search": true,
        "company_locations": ["US"]
      },
      "per_page": 25,
      "page": 1
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.pubrio.com/people/search",
      headers={
          "Content-Type": "application/json",
          "pubrio-api-key": "YOUR_API_KEY",
      },
      json={
          "people_titles": ["VP of Engineering", "CTO"],
          "company_filters": {
              "technologies": ["Kubernetes", "Docker"],
              "is_enable_similarity_search": True,
              "company_locations": ["US"],
          },
          "per_page": 25,
          "page": 1,
      },
  )
  print(response.json())
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.pubrio.com/people/search", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "pubrio-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      people_titles: ["VP of Engineering", "CTO"],
      company_filters: {
        technologies: ["Kubernetes", "Docker"],
        is_enable_similarity_search: true,
        company_locations: ["US"],
      },
      per_page: 25,
      page: 1,
    }),
  });
  console.log(await response.json());
  ```
</CodeGroup>

***

## `company_filters`: держите ключи уровня компании сгруппированными

Обёртка `company_filters: {...}` — рекомендуемый способ отправки фильтров уровня компании: она визуально отделяет, какие ключи фильтруют *человека*, а какие — *компанию*, и соответствует форме, которую уже использует [Monitors](/ru/developer-guides/introduction), поэтому payload'ы без изменений переносятся между конфигурациями поиска и монитора.

Оба стиля работают; движок разворачивает обёрнутую форму на верхний уровень перед обработкой, и **ключи верхнего уровня побеждают при конфликте**:

<CodeGroup>
  ```json Обёрнутый (рекомендуется) theme={null}
  {
    "people_titles": ["VP of Engineering"],
    "company_filters": {
      "technologies": [37, 152],
      "founded_dates": [2015, 2023],
      "company_locations": ["US"]
    }
  }
  ```

  ```json Плоский (тоже работает) theme={null}
  {
    "people_titles": ["VP of Engineering"],
    "technologies": [37, 152],
    "founded_dates": [2015, 2023],
    "company_locations": ["US"]
  }
  ```
</CodeGroup>

Когда вы добавляете переопределение `filter_conditions` для ключа уровня компании, размещайте его **внутри** `company_filters`, чтобы оно перемещалось вместе с ключами, которые переопределяет.

### Та же форма у вариантов `/search/similar`

`POST /companies/search/similar` и `POST /people/search/similar` принимают **то же тело фильтров**, что и их обычные аналоги (включая обёртку `company_filters` и `filter_conditions`). Каждый добавляет сверху шаг сходства:

|                             | Что нужно дополнительно                                                                                                    | Что вы получаете дополнительно                                                                     |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `/companies/search/similar` | Референсная компания — `domain_search_id`, `domain`, `linkedin_url` или `domains`                                          | Каждый результат получает `similarity_score` (float, 0-1), строки упорядочены по убыванию схожести |
| `/people/search/similar`    | Референсный человек/должность — один из `people_titles`, `people_search_id`, `linkedin_url`, `linkedin_urls` или `peoples` | То же — `similarity_score` на строку, упорядочено по схожести                                      |

Конверт ответа в остальном идентичен стандартному эндпоинту `search`. Фильтры сужают пул кандидатов *до* применения ранжирования по сходству — поэтому сочетание `company_locations: ["US"]` с `/people/search/similar` возвращает наиболее близких людей из США к вашим референсным должностям, что и является паттерном «найти больше похожих на X в этих ограничениях».

<Note>
  В отличие от стандартных эндпоинтов `/search`, `/search/similar` **не** возвращает точное значение `pagination.total_entries` — оно ограничено, поскольку поиск похожих ранжирует результаты по релевантности и отображает только лучшие совпадения. Используйте поиск похожих, чтобы найти *лучшие* совпадения, а не чтобы перечислить каждое.
</Note>

***

## AND против OR — единственное решение, которое вы принимаете на фильтр

Мультизначные фильтры (`technologies`, `verticals`, `keywords`, `categories`, …) принимают массив. Оператор определяет, что означает «совпадение»:

<Tabs>
  <Tab title="OR (по умолчанию)">
    **Совпадает любое значение.** Возвращает строки, чей массив пересекается с вводом.

    ```json theme={null}
    {
      "technologies": ["Python", "PostgreSQL", "Kubernetes"],
      "is_enable_similarity_search": true
    }
    ```

    Компания включается, если её технологический стек содержит **хотя бы одну** из `Python`, `PostgreSQL` или `Kubernetes`. Компилируется в Postgres `column && ARRAY[...]`.

    Используйте, когда: вам нужен широкий охват — «интересуется *любым* из этого», «находится в *любой* из этих стран».
  </Tab>

  <Tab title="AND">
    **Совпадает каждое значение.** Возвращает строки, чей массив содержит каждое значение из ввода.

    ```json theme={null}
    {
      "technologies": [37, 152, 408],
      "filter_conditions": [
        { "key": "technologies", "operator": "and" }
      ]
    }
    ```

    Числовые ID тегов берутся из `GET /technologies?search_term=python` (и аналогичных). **Не комбинируйте `is_enable_similarity_search: true` с AND на одном и том же ключе** — сходство расширяет каждый свободный текстовый термин во множество ID тегов, и `@>` затем требует, чтобы строка содержала их все, что почти всегда возвращает ноль.

    Компания включается, только если её технологический стек содержит **все из** `[37, 152, 408]`. Компилируется в Postgres `column @> ARRAY[...]`.

    Используйте, когда: вам нужна точность — «использует *все из* этих технологий вместе», «отмечена *всеми* этими вертикалями».
  </Tab>
</Tabs>

<Note>
  Фильтры, не перечисленные в `filter_conditions`, используют оператор по умолчанию (OR внутри массива, AND между разными ключами фильтров). Вы объявляете только переопределения — никогда значения по умолчанию.
</Note>

***

## Что можно переопределить

Каждый эндпоинт принимает переопределения для своего набора ключей. Ключи берутся из перечисления OpenAPI на каждой схеме `*_filter_conditions`:

<CardGroup cols={3}>
  <Card title="Эндпоинт компаний" icon="building" href="/ru/api-reference/endpoint/companies/search">
    Ключи `company_filter_conditions`: `keywords`, `verticals`, `vertical_categories`, `vertical_sub_categories`, `technologies`, `categories`, `advertisement_target_locations`, `advertisement_exclude_target_locations`, `advertisement_search_terms`, `places`, `exclude_places`, `job_exclude_locations`.
  </Card>

  <Card title="Эндпоинт людей" icon="user" href="/ru/api-reference/endpoint/people/search">
    Ключи `people_filter_conditions` (делегируются движку компаний): `keywords`, `verticals`, `vertical_categories`, `vertical_sub_categories`, `technologies`, `categories`, `places`, `exclude_places`, плюс `social_media`.
  </Card>

  <Card title="Эндпоинт рекламы" icon="bullhorn" href="/ru/api-reference/endpoint/companies/advertisements_search">
    Ключи `ads_filter_conditions`: `target_locations`, `exclude_target_locations`. Набор меньше, потому что реклама фильтруется только по стране показа.
  </Card>
</CardGroup>

<Tip>
  При использовании `/people/search` ключ `filter_conditions[].key` для локаций уровня компании использует **голое** имя из движка компаний — `places`, `exclude_places` — а не имя с префиксом people-API (`company_places`). См. [People + Company Filters](/ru/developer-guides/filters/people-with-company-filters#key-remap-reference).
</Tip>

***

## Советы по производительности

<AccordionGroup>
  <Accordion title="Сначала фильтруйте по индексированным столбцам" icon="bolt">
    Локации, диапазоны числа сотрудников и `founded_dates` индексированы и сокращают набор кандидатов быстрее, чем свободный текст или фильтры по вертикалям. Сочетайте их с одним-двумя точными фильтрами, прежде чем прибегать к поиску по сходству.
  </Accordion>

  <Accordion title="Не злоупотребляйте AND на больших массивах" icon="triangle-exclamation">
    `column @> ARRAY[a, b, c, …]` требует наличия каждого значения. Кардинальность растёт быстро — AND по 10 технологиям в категории со средним значением 3 тега технологий возвращает почти ноль строк и вынуждает выполнить полное сканирование. Предпочитайте 2-4 значения на фильтр AND; переключайтесь на OR для исследовательских запросов.
  </Accordion>

  <Accordion title="Используйте is_enable_similarity_search для свободного текста" icon="wand-magic-sparkles">
    Если вы не можете предоставить slug ID (вертикали, технологии, категории) и у вас есть только строки свободного текста, установите `is_enable_similarity_search: true` и `similarity_score: 0.7`. Движок разрешает совпадения перед применением фильтра — гораздо дешевле, чем сканирование текста.
  </Accordion>

  <Accordion title="Предпочитайте диапазоны спискам перечислений для размера и выручки" icon="arrows-left-right">
    `employees: [[201, 500], [501, 1000]]` (массив диапазонов) и `revenues: [1000000, 5000000]` (единый диапазон мин/макс) быстрее и более идиоматичны, чем длинные списки ID.
  </Accordion>
</AccordionGroup>

***

## Фильтры активности рекламы

`/companies/search` может фильтровать по рекламной активности компании — сколько рекламы она размещает, есть ли активные объявления сейчас, какие платформы и форматы использует и как она ранжируется относительно других рекламодателей в определённой стране. `POST /companies/advertisements/search` также принимает все эти фильтры (`advertisement_active_ads`, `advertisement_running_ads`, `advertisement_total_ads`, `advertisement_platform_count`, `advertisement_format_count`, `advertisement_impressions_estimate`, `advertisement_formats`, `advertisement_country_activity`) — объявление включается, если компания-владелец соответствует границе.

| Фильтр                                                                             | Форма                                                                                                                                                   | Область охвата |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `advertisement_active_ads`, `advertisement_running_ads`, `advertisement_total_ads` | диапазон `[min, max]`                                                                                                                                   | Все страны     |
| `advertisement_platform_count`, `advertisement_format_count`                       | диапазон `[min, max]`                                                                                                                                   | Все страны     |
| `advertisement_impressions_estimate`                                               | диапазон `[min, max]`                                                                                                                                   | Все страны     |
| `advertisement_formats`                                                            | массив — `image`, `video`, `text`, `carousel`, `dynamic_product`, `document`, `message`, `event`, `article`, `spotlight`, `follow`, `job`, `engagement` | Все страны     |
| `advertisement_platforms`                                                          | массив — `linkedin`, `facebook`, `google`, `tiktok`, `apple` (`meta` принимается как псевдоним `facebook`)                                              | Все страны     |
| `advertisement_publisher_platforms`, `advertisement_exclude_publisher_platforms`   | массив — `facebook`, `instagram`, `messenger`, `threads`, `audience_network`                                                                            | Все страны     |
| `advertisement_status`                                                             | массив — `currently_running` (есть зафиксированные объявления), `active_last_30_min` (записи объявлений менялись за последние 30 минут)                 | Все страны     |
| `advertisement_country_activity`                                                   | объект, см. ниже                                                                                                                                        | Одна страна    |

Используйте `null` для открытой границы — `[1, null]` означает «не менее 1», `[null, 500]` означает «500 или меньше».

```json theme={null}
{
  "advertisement_active_ads": [1, null],
  "advertisement_formats": ["video"]
}
```

### Ранжирование внутри страны

`advertisement_country_activity` привязывает ранг, процентиль и оценку объёма к одной стране за раз — ранг рекламы компании в США ничего не говорит о её ранге в Германии, поэтому `country` обязателен:

```json theme={null}
{
  "advertisement_country_activity": {
    "country": "US",
    "rank": [null, 500]
  }
}
```

<Warning>
  **`rank` отсчитывается от крупнейшего рекламодателя, как в гонке.** `1` — крупнейший рекламодатель в этой стране, и число *растёт* по мере того, как объём рекламы *снижается*. Чтобы найти **крупнейших** рекламодателей, фильтруйте `rank` с **низкой** верхней границей — `[null, 500]` это топ-500. Фильтрация `[500, null]` находит всех, кто **вне** топ-499, что противоположно «крупному рекламодателю». Если вам нужна независимая от масштаба версия, работающая одинаково независимо от того, сколько рекламодателей в этой стране, используйте вместо этого `percentile` — он работает в обратном направлении, поэтому **более высокое** число означает **более крупного** рекламодателя: `[90, null]` это топ-10%.
</Warning>

Комбинируйте `advertisement_country_activity` со общестрановыми фильтрами выше в одном запросе — например, «в топ-500 в США и имеет не менее 100 активных объявлений по всей компании»:

```json theme={null}
{
  "advertisement_country_activity": { "country": "US", "rank": [null, 500] },
  "advertisement_active_ads": [100, null]
}
```

***

## Следующие шаги

<CardGroup cols={2}>
  <Card title="filter_conditions" icon="code-merge" href="/ru/developer-guides/filters/filter-conditions">
    Справочник — каждый поддерживаемый ключ, каждое значение по умолчанию и готовые к копированию рецепты AND/OR.
  </Card>

  <Card title="People + Company Filters" icon="users-rectangle" href="/ru/developer-guides/filters/people-with-company-filters">
    Используйте любой фильтр компании внутри `/people/search`. Главная новая возможность единого движка.
  </Card>

  <Card title="Справочник Company Search" icon="building" href="/ru/api-reference/endpoint/companies/search">
    Полная схема запроса/ответа для `/companies/search`.
  </Card>

  <Card title="Справочник People Search" icon="user" href="/ru/api-reference/endpoint/people/search">
    Полная схема запроса/ответа для `/people/search`.
  </Card>
</CardGroup>

<Note>
  Ищете описание фильтрации на стороне дашборда? См. [Фильтрация и экспорт контактов](/ru/knowledge-base/concepts/search-filters) в базе знаний.
</Note>
