---
title: Filters
slug: filters
docTags: 
createdAt: 2022-09-15T14:52:30.000Z
---

Filters are used by multiple HyperPortal features, they allow to display/get/modify content depending on set conditions.

## ALL/ANY condition&#x20;

With this setting, you can decide whether all conditions should be met or only one.

Example - let\`s create two conditions for the list view of the contact entity. The first condition - the country is Belgium. The second condition - gender is female.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/7aI21hoUpSH_oiRWCq5u1_image.png" size="70" width="416" height="889" position="center" darkWidth="416" darkHeight="889" showCaption="false"}

If 'ALL' is chosen, only contacts that meet two conditions will be displayed.

![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/G4HYhMna9JZ4ikBfSHjzk_image.png)

If we click on 'meet any of the following conditions' the system will display contacts that meet any of the conditions.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/apEKalXj31nLEA5spHEOi_image.png" size="58" width="405" height="314" position="center" darkWidth="405" darkHeight="314" showCaption="false"}

![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/P7yp4p-9OAnIegiWNTI-l_image.png)

## Condition groups

The group of conditions allows us to use multiple conditions as one single condition.

Next to the 'add condition' button, there is an 'add group' button. Instead of one condition, you can add a group of conditions.&#x20;

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/vdVedxgr_ajzZcjuxgN0E_image.png" size="70" width="402" height="643" position="center" darkWidth="402" darkHeight="643" showCaption="false"}

Inside the condition group, you can add other conditions or groups.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/RTOkx8zxo67ttuDrmNfdS_image.png" size="80" width="416" height="314" position="center" darkWidth="416" darkHeight="314" showCaption="false"}

Group conditions are useful when you want to display/get/modify multiple groups of items. For example, I can create a filter that shows me blue diesel cars and red electric cars. First I need to create two groups.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/wOsgCxNe23-f3Xem0WhX4_image.png" size="70" width="395" height="638" position="center" darkWidth="395" darkHeight="638" showCaption="false"}

The first group will contain conditions for blue diesel cars, and the second group will contain conditions for  red electric cars. For the main filter, we should select 'meet any conditions', so the cars from each group will appear. We should also select 'meet all' in each group.&#x20;

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/H-oQJovvMVATmdIt57z-L_image.png" size="70" width="386" height="633" position="center" darkWidth="386" darkHeight="633" showCaption="false"}

The result of this filter will show two groups of cars.

![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/gp6dTQEZnwmwMb7OCjJUf_image.png)

## "Is Any Of" and "Is Not Any Of" operators:

We have added new filter options, **"Is Any Of"&#x20;**&#x61;nd **"Is Not Any Of"** with support for bulk pasting.

**Rules:&#x20;**

- These filter operators work with the following property types: plain text, Entity, Phone, Email, and Link.
- Item Limit: Supports up to 1,000 items in the filter.
- If you input more than 1000 items in the field, then the remaining items will be copied to the clipboard
- If the filter exceeds 1000 values, the "+ Add condition" button will be disabled

![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/knKooWhKeSrTy4f-LO8P-_screenshot-2024-11-18-at-152437.png)



For the Safari browser, the **"Copy"** button was added, in other browsers the values that exceed 1000 are automatically added to your clipboard after pasting:

- Warning notification popup

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/nmyyANmQe76Ar57o2B4Ac_screenshot-2024-11-19-at-162448.png" size="80" width="801" height="262" position="center" darkWidth="801" darkHeight="262" showCaption="false"}



- Error notification popup

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/fMB23WICDLymkIfnQjh8M_screenshot-2024-11-19-at-162605.png" size="80" width="796" height="215" position="center" darkWidth="796" darkHeight="215" showCaption="false"}

**Use case example:**

1\. Copy the items from the "country" column in your Excel file.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/IhP48YSu66GGo1gxEIs2Y_screenshot-2024-11-19-at-171317.png" size="24" width="202" height="364" position="center" darkWidth="202" darkHeight="364" showCaption="false"}

2\. In HyperPortal, click the "Edit View" button.

3\. Add a filter for the entity property "Country" (<font color="#ff0000">1</font>) and click on the dropdown where you can choose    &#x20;

- "Is Any Of" - the table displayed only items that were added to the filter (<font color="#ff0000">2</font>)
- "Is Not Any Of" - the table displays all elements except those added to the filter (<font color="#ff0000">2</font>)

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/9-fY7pcJvh0DZ3_h9eaQ__screenshot-2024-11-19-at-171704.png" size="80" width="1536" height="738" position="center" darkWidth="1536" darkHeight="738" showCaption="false"}

&#x20;4\. Paste the copied "Country" values into the "Search Country" field.

::Image[]{src="https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/eLF1BydOfCYQWbt0ybJRa_screenshot-2024-11-19-at-171849.png" size="80" width="1470" height="752" position="center" darkWidth="1470" darkHeight="752" showCaption="false"}

5\. Click the "Show Result" button to apply the filter.

## Dynamic User Filter "⚡️ Me (dynamic)"

The **“Me” (dynamic)** filter allows dashboards, views, and charts to automatically adapt to the currently logged-in user.

Instead of selecting a fixed user (e.g., *Owner = Nicolas*), you can configure: "Owner = Me (dynamic)"

![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/wPeTFN3UHlcoqumxfqN2I_image.png)



![](https://api.archbee.com/api/optimize/5goaGPkGyPYxtK7K75CEC/4PxSGOGcxAOOul1wf-lDx_image.png)

At runtime, the system resolves **“Me (dynamic)”** to the authenticated user viewing the data.

This enables a single dashboard or view configuration to be reused by multiple users while still displaying user-specific data.

**Business Impact**

Previously, user-specific dashboards required separate configurations such as:

- Owner = Nicolas
- Owner = Ilya

This resulted in:

- Duplicate dashboards
- Poor scalability

With the **dynamic user filter**, one configuration works for all users.

**Scope & Limitations**

The **“Me” (dynamic)** value is available in:

- View filters
- Table filters
- Chart filters
- Dashboard filters

The dynamic option is available **only for properties where definitionId = Contact**.
It can be used exclusively with Contact-based relational fields (e.g., Owner).



## Fuzzy search (Similar to)

Fuzzy search is the `FUZZY` filter operator that finds values **spelled with typos, in**
**a different case, without diacritics, or in a different word order**. Use it anywhere
resilience to human input errors is needed â€” from ordinary record search to matching
"near-duplicates".

This document explains what the `FUZZY` operator gives you and how exactly it works
under the hood â€” with a focus on **how a value is split into words/tokens** by the
analyzer.

***

### 1. In brief

- The `FUZZY` operator tolerates **up to 2 typos per word** (edit distance of 2).
- Case and diacritics **don't matter**: `MÃ¼ller` = `muller` = `MULLER`, `Å koda` = `skoda`.
- **Word order doesn't matter**: the query `jhon doe` finds the record `Doe, John`.
- **Every query word must match** (AND between words): an extra word narrows the result.
- It is **not** a substring search: `berg` does not find `iceberg`. Matching is against
  whole tokens (words), not their middle.
- It works on the **analyzed** (word-split) field, not on the "raw" `.keyword` value used
  by the `IS` / `CONTAINS` / `STARTS_WITH` operators.

***

### 2. What it does and when to use it

The regular operators compare the value as a whole:

| Operator                    | What it does                                                       |
| --------------------------- | ------------------------------------------------------------------ |
| `IS`                        | exact match of the whole string (case- and diacritics-insensitive) |
| `CONTAINS`                  | the value contains a substring                                     |
| `STARTS_WITH` / `ENDS_WITH` | the value starts/ends with a substring                             |
| `FUZZY`                     | **each query word matches with up to 2 typos, in any order**       |

Typical scenarios for `FUZZY`:

- **Search with typos:** the user searches for `Volkwagen`, while the database has `Volkswagen`.
- **Different word order:** `John Smith` and `Smith John`.
- **Different spelling/diacritics:** `Muller`, `MÃ¼ller`, `Mueller`.
- **Detecting "near-duplicates"** when data is entered by people and minor discrepancies
  are inevitable.

:::BlockQuote
`FUZZY` is intended for **text** values (names, titles, addresses, e-mail). For dates,
numbers, and checkboxes use exact operators (`IS`, comparisons).
:::

***

### 3. How it works under the hood

Fuzzy search has two sides:

1. **Indexing** â€” how a value stored in a record is split into tokens in advance.
2. **Query** â€” how the string typed by the user is turned into a fuzzy condition.

Matching happens **between the value's tokens and the query's words**. So it is important
to understand tokenization first.

3.1. Indexing: splitting a value into tokens (the `default` analyzer)

All text properties (`text`, `multitext`, `richtext`, `file`, `entity`, `phoneNumber`,
`email`) are indexed in two ways at once:

```jsonc
{
  "type": "text",
  "analyzer": "default",     // â† analyzed field: the value is split into tokens
  "fields": {
    "keyword": {
      "type": "keyword",
      "ignore_above": 256,
      "normalizer": "keyword_normalizer"  // â† raw value as a whole (used by IS/CONTAINS/â€¦)
    }
  }
}
```

- The `propertyId` field is **analyzed**: the value is run through the `default` analyzer
  and stored as a set of tokens. **This is what&#x20;**`FUZZY`**&#x20;works on.**
- The `propertyId.keyword` field is the **whole** value (only folded by case and
  diacritics via the `keyword_normalizer`). It is used by `IS`, `CONTAINS`,
  `STARTS_WITH`, `ENDS_WITH`, `IN`.

The `default` analyzer is a chain of a tokenizer and filters:

```mermaid
flowchart LR
  A["source value"] --> B["icu_tokenizer<br/>split into words"]
  B --> C["word_split<br/>extra split on hyphens,<br/>case, digits"]
  C --> D["icu_normalizer<br/>lowercase,<br/>Unicode normalization"]
  D --> E["icu_folding<br/>strip diacritics"]
  E --> F["tokens in the index"]
```

```jsonc
"default": {
  "type": "custom",
  "tokenizer": "icu_tokenizer",
  "filter": ["word_split", "icu_normalizer", "icu_folding"]
}
```

What each step does:

1. `icu_tokenizer` â€” splits text into words by the Unicode text-segmentation rules
   (UAX #29): on whitespace, punctuation, and boundaries between different writing
   scripts. Works correctly for most languages.
2. `word_split` (the `word_delimiter` filter with `preserve_original: true`) â€”
   **additionally** breaks tokens up while keeping the original variant:
   - on intra-word delimiters: `Wi-Fi` â†’ `Wi`, `Fi`;
   - on the letter/digit boundary: `X5` â†’ `X`, `5`;
   - on case change (camelCase): `iPhone` â†’ `i`, `Phone`;
   - `preserve_original: true` â€” the original token is kept too (`iPhone`).
3. `icu_normalizer` â€” lowercases and performs Unicode normalization (a single
   canonical form of characters).
4. `icu_folding` â€” strips diacritics and folds characters to their base forms:
   `cafÃ©` â†’ `cafe`, `MÃ¼ller` â†’ `muller`, `Å koda` â†’ `skoda`.

Tokenization examples (illustrative â€” the exact split is determined by ICU rules):

| Field value     | Tokens in the index    |
| --------------- | ---------------------- |
| `Å koda Superb` | `skoda`, `superb`      |
| `MÃ¼ller`       | `muller`               |
| `iPhone`        | `iphone`, `i`, `phone` |
| `e-mail`        | `e`, `mail`            |
| `BMW X5`        | `bmw`, `x5`, `x`, `5`  |
| `John Doe`      | `john`, `doe`          |

**Key idea:** a value in a record is stored not as one string but as a set of separate
word-tokens. Fuzzy search matches the query words against these tokens individually.

:::BlockQuote
For comparison, the `.keyword` field uses the `keyword_normalizer` â€” it applies only
`icu_folding` (case + diacritics) and does **not** split the value into words. So
`John Doe` is stored in `.keyword` as a single `john doe`.
:::

3.2. Query: how the fuzzy condition is built

The string entered by the user is turned into a fuzzy condition as follows:

1. An empty value (`null`, `undefined`, empty string) â†’ `FILTER_INVALID` error.
2. The input is trimmed and **split on whitespace** (`\s+`) into words. Repeated and
   surrounding spaces are collapsed.
3. Each word becomes a term `field:word~2`:
   - it targets the **analyzed** field, **not** `.keyword`;
   - the `~2` suffix is Lucene fuzzy-search syntax: **edit distance 2**;
   - special characters are escaped before the `~2` suffix is appended.
4. If there are several words, they are combined with `AND` and wrapped in parentheses.

Conversion examples:

| User input       | Generated condition                               |
| ---------------- | ------------------------------------------------- |
| `jhon`           | `name:jhon~2`                                     |
| `jhon doe`       | `(name:jhon~2 AND name:doe~2)`                    |
| `foo bar baz`    | `(name:foo~2 AND name:bar~2 AND name:baz~2)`      |
| `  jhon   doe  ` | `(name:jhon~2 AND name:doe~2)` (spaces collapsed) |
| `jh:on`          | `name:jh\:on~2` (colon escaped)                   |

Why this gives "word-order independence": each query word is searched among **any** of
the field's tokens independently, and `AND` requires that **all** words are found. Order
plays no role.

3.3. What "edit distance 2" means

`~2` is the maximum **Damerauâ€“Levenshtein distance** between a query word and a token in
the index. Up to 2 operations per word are allowed, where one operation is:

- inserting one character (`jon` â†’ `john`),
- deleting one character (`johnn` â†’ `john`),
- substituting one character (`jahn` â†’ `john`),
- **transposing two adjacent characters** (`jhon` â†’ `john`).

`2` is the maximum value that Lucene fuzzy search supports. The query word also passes
through the field analyzer before matching, so case and diacritics in the query don't
matter either.

***

### 4. Examples: what matches and what doesn't

A record with the `name` property value = `John Doe` â†’ tokens `john`, `doe`.

| Query (`FUZZY`)                  | Matches? | Why                                                    |
| -------------------------------- | -------- | ------------------------------------------------------ |
| `jhon`                           | âœ…      | `jhon` â†’ `john`: transposition = 1 operation (â‰¤ 2) |
| `jon`                            | âœ…      | inserting `h` = 1 operation                            |
| `jhon doe`                       | âœ…      | both words matched (AND), order doesn't matter         |
| `doe john`                       | âœ…      | word order doesn't matter                              |
| `john smith`                     | âŒ       | `smith` matched no token â†’ AND fails                 |
| `berg` (for the value `iceberg`) | âŒ       | not a substring: `berg`â†’`iceberg` = 3 operations     |

Diacritics and case: the record `MÃ¼ller` (token `muller`) matches the queries `muller`,
`Muller`, `MÃœLLER`, `mueller` (the last one â€” 1 deletion).

***

### 5. Limitations and pitfalls

- **No more than 2 typos per word.** A heavily distorted word (`Volswgn` instead of
  `Volkswagen`) won't match.
- **Short words cause false positives.** With distance 2, the word `ford` matches `word`,
  `form`, `fort`, `food`, and so on. For short values (part numbers, 3â€“4-character codes)
  fuzzy search is best avoided.
- **It is not a substring search.** For "contains a fragment" use `CONTAINS`.
- **AND between words.** Every extra word in the query narrows the result â€” all words must
  match.
- **Numbers and punctuation are split** by the `word_split` filter, so behavior on codes,
  part numbers, and SKUs may be surprising â€” prefer `IS`/`CONTAINS`.
- **Empty value is not allowed:** an empty string leads to a `FILTER_INVALID` error.
