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

# Campos pesquisáveis

> Por que uma coisa não aparece na busca — as três buscas diferentes, o que fica achável de graça, o que precisa declarar e quando usar indexed_fields.

A pergunta que aparece toda semana: *"por que não acho isso?"*. A resposta depende de que tipo de busca você quer, e são três coisas diferentes.

***

## As três buscas

| Você quer                                                    | Ferramenta      | Devolve    | Precisa declarar?    |
| ------------------------------------------------------------ | --------------- | ---------- | -------------------- |
| achar **uma** coisa por um identificador (`ABC1D23`, um CPF) | `search_entity` | 1 entidade | depende — ver abaixo |
| achar **todas** que casam com um campo comum (`cor = prata`) | `run_cypher`    | uma lista  | **não**              |
| achar por nome parecido (`Ana Sousa`)                        | `search_entity` | ranqueado  | não                  |

***

## 1. Achar pelo identificador

### De graça: o próprio `id_field`

Um nó **sem nenhum `er_fields`** já é achável pelo valor da sua chave. A plataforma grava duas linhas no índice:

```text theme={null}
Ticket.external_id@zendesk    123145123                        ← a busca acha por esta
external_id                   zendesk:clean/…:123145123        ← esta resolve internamente
```

Então um `Ticket` com `id_field: external_id` e nada mais **já responde** a busca por `123145123`.

<Tip>
  Não declare `er_fields` só para isso — além de desnecessário, tira o nó do caminho de ingestão mais rápido.
</Tip>

### Declarando: qualquer outra coluna

Para achar por uma coluna que **não é** a chave — o número do contrato quando a chave é `id`, o CPF, a placa — declare em `er_fields`:

```yaml theme={null}
- label: Contrato
  id_field: id                   # a chave do sistema
  er_fields: [numero_contrato]   # o que a pessoa tem na mão
```

Agora `CT-2026-0001` acha o contrato.

### Em qualquer formato

Os dois lados normalizam com a mesma regra, então o formato não importa:

```text theme={null}
você digita "111.222.333-44"  → 11122233344 → Ana
você digita "11122233344"     → 11122233344 → Ana
você digita "ABC1D23"         → abc1d23     → o carro
você digita " m-123456 "      → m-123456    → o imóvel
```

A resposta vem com `match_tier: identifier:<campo>`, então você sabe **por qual campo** achou.

***

## 2. Achar todas que casam com um campo comum

`cor`, `status`, `ano`, `modelo`, faixa de valor. Isso **não é identificador** — não declare em `er_fields`, ou você funde tudo que compartilha o valor.

Toda coluna em `properties` já está no nó do grafo. Então:

```cypher theme={null}
MATCH (c:Carro) WHERE c.cor = 'prata'
RETURN c.entity_id, c.display_name, c.modelo
```

```text theme={null}
| entity_id                            | display_name | modelo   |
| 017788bb-b6c8-55f2-b258-bc2549b3599f | abc1d23      | Fiat Uno |
```

Funciona para qualquer propriedade, qualquer operador, e o resultado já vem filtrado por ACL. **Não precisa declarar nada** — a coluna estar em `properties` basta.

O `get_schema` lista as propriedades reais de cada label, então dá para descobrir o que existe antes de filtrar.

<Note>
  **Por que não pela busca de identificador?** Porque o índice de identidade tem uma linha por chave: dois carros prata colidiriam. E porque essas duas perguntas são diferentes — uma resolve *um* valor em *uma* entidade, a outra filtra *muitas*.
</Note>

### Quando o grafo cresce: `indexed_fields`

Nada a declarar é verdade para o **resultado**. Não é verdade para o **custo**.

Sem declarar nada, o `MATCH (c:Carro) WHERE c.cor = 'prata'` lê **todo nó da label** e descarta o que não casa — um `NodeByLabelScan`. Com 200 carros, ninguém percebe. Com 100 mil, percebe.

Declarar a coluna como indexada faz o worker criar um índice de propriedade no grafo:

```yaml theme={null}
- label: Carro
  source: clean/detran_veiculos
  id_field: placa
  er_fields: [placa, chassi, renavam]
  indexed_fields: [cor, ano]      # o que a operação FILTRA
  properties: [placa, chassi, renavam, modelo, cor, ano]
```

A mesma consulta passa a ser um `NodeIndexSeek`: o banco pula direto para os nós prata em vez de ler os 100 mil. Dá para conferir com `EXPLAIN` antes e depois — é a diferença entre as duas palavras no plano.

Três coisas que precisam estar claras:

* **`indexed_fields` não é `er_fields`.** Um acelera filtro, o outro declara identidade e funde entidades. Pôr `cor` em `er_fields` funde todos os carros prata numa entidade só.
* **`indexed_fields` não faz o `search_entity` achar "prata".** Ele acelera o Cypher. A caixa de busca continua sendo sobre identificadores.
* **Cada entrada é um índice a manter**, com custo de escrita e de disco. Declare o que a operação filtra de verdade, não tudo que existe.

O `get_schema` informa ao agente quais propriedades estão indexadas — e ele descobre isso **perguntando ao banco**, não lendo a ontologia. Índice declarado mas nunca criado (porque o worker não rodou) simplesmente não aparece.

***

## 3. Achar por nome parecido

Cai nos tiers de texto: exato, depois trigrama, depois vetor. Nada a declarar — funciona sobre o nome que a plataforma derivou.

***

## Como o rótulo é escolhido

Você não declara. A ordem é:

1. **um campo de nome** — `name`, `nome`, `razao_social`, `title`, `full_name`…
2. **o primeiro `er_field` que tiver valor**, na ordem que você declarou
3. **o `id_field`**

Por isso `er_fields: [placa, chassi, renavam]` faz o carro aparecer como `abc1d23` e não como `9BWZZZ377VT004251`: você já disse qual identificador as pessoas usam.

E-mail **não** conta como nome. Se for o melhor rótulo que a linha tem, ele chega lá pelo passo 2, por mérito próprio.

***

## Tabela de decisão

| O caso                                                    | O que fazer                                                    |
| --------------------------------------------------------- | -------------------------------------------------------------- |
| achar ticket pelo número, e o número é a chave            | nada                                                           |
| achar contrato pelo número, mas a chave é `id`            | `er_fields: [numero_contrato]`                                 |
| achar pessoa por CPF **e** juntar as fontes               | `er_fields: [cpf]`                                             |
| achar todo carro prata                                    | `run_cypher`, nada a declarar                                  |
| achar todo carro prata, e são 100 mil carros              | `indexed_fields: [cor]`                                        |
| achar por CPF, mas a coluna se chama `documento`          | `er_fields: [documento]` mais `normalizers: {documento: cpf}`  |
| achar por CPF, e a fonte estrangeira chama de `ID_BRAZIL` | `er_fields: [cpf]` mais `identifier_columns: {cpf: ID_BRAZIL}` |
| achar por nome parecido                                   | nada                                                           |
| campo que se repete (`status`, `cidade`)                  | **nunca** em `er_fields` — use `run_cypher`                    |

<CardGroup cols={2}>
  <Card title="Padrões e armadilhas" icon="triangle-exclamation" href="/admin/ontology-patterns">
    A regra de ouro, os erros que já aconteceram e o checklist antes do apply.
  </Card>

  <Card title="Escrevendo uma ontologia" icon="pen-to-square" href="/admin/ontology-writing">
    Voltar à estrutura do arquivo, campo a campo.
  </Card>
</CardGroup>
