# Search Operators in Hister: How to Use Phrases, Wildcards, and Negation

> Master Hister search operators like phrases, wildcards, and negation. Enhance your searches with exact sequence and partial term matching using `indexer.Query`.

- Repository: [Adam Tauber/hister](https://github.com/asciimoo/hister)
- Tags: how-to-guide
- Published: 2026-08-27

---

**Hister supports three core query operators—double-quoted phrases for exact sequence matching, asterisk and question mark wildcards for partial term matching, and minus sign or NOT keyword negation—that can be combined within the `indexer.Query` structure processed by [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go) and sent via the client's `/search` endpoint.**

The `asciimoo/hister` search engine provides a lightweight yet powerful query language for filtering indexed documents. Understanding the available **search operators in Hister** enables precise document retrieval beyond simple keyword matching. The query parsing and execution logic resides primarily in the server-side indexer package, with the client responsible only for transmitting the constructed `Query` object to the search endpoint.

## Core Search Operators in Hister

### Exact Phrase Matching with Double Quotes

Enclose search terms in double quotes (`"exact phrase"`) to match sequences in a specific order with exact spacing. The tokenizer treats the entire quoted string as a single unit, ensuring that `"quick brown fox"` only returns documents containing that precise contiguous string. In [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go), the parser identifies quoted substrings prior to tokenization to preserve their boundaries.

```go
q := &indexer.Query{
    Query: `"my private notes"`,
}
res, _ := client.Search(q) // Returns only documents containing the exact phrase

```

### Wildcard Searches with Asterisks and Question Marks

Use trailing wildcards to match partial terms without specifying the complete word. Append `*` to match zero or more characters (e.g., `doc*` matches *document*, *docs*, *documentation*), or append `?` to match exactly one character. These wildcards enable efficient prefix matching across term variations.

```go
q := &indexer.Query{
    Query: `report*`,
}
res, _ = client.Search(q) // Matches "report", "reports", "reporting", etc.

```

### Term Negation with Minus Signs and NOT

Exclude documents containing specific terms using the minus sign prefix (`-term`) or the explicit `NOT` keyword before the term. The indexer filters out any results containing the negated token. Multiple negations can be combined in a single query to progressively refine the result set.

```go
q := &indexer.Query{
    Query: `project -draft`,
}
res, _ = client.Search(q) // Finds "project" but excludes any results containing "draft"

```

## Combining Multiple Search Operators

You can layer phrases, wildcards, and negation within a single query string. As implemented in `asciimoo/hister`, the parser processes these combinations in [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go) before marshaling the query to JSON for the search engine. This capability supports complex retrieval patterns such as exact phrases combined with partial matches and exclusion criteria.

```go
q := &indexer.Query{
    Query: `"meeting notes" agenda* -cancelled`,
}
res, _ = client.Search(q) 
// Exact phrase "meeting notes" + words starting with "agenda" + excludes "cancelled"

```

## Implementation Architecture

The search operator logic resides in [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go), which defines the `Query` struct and handles the transformation of textual queries into the engine's internal representation. According to the source code, the client implementation in [`client/search.go`](https://github.com/asciimoo/hister/blob/main/client/search.go) merely forwards the constructed `indexer.Query` structure via HTTP POST to the `/search` endpoint. The server-side indexer performs all tokenization, wildcard expansion, and negation filtering before returning the filtered document set.

## Summary

- **Phrase operator**: Use double quotes (`"exact phrase"`) to match literal strings in a specific order and spacing.
- **Wildcard operator**: Use `*` for zero-or-more character matching and `?` for single-character matching at the end of terms.
- **Negation operator**: Use `-term` or `NOT term` syntax to exclude documents containing specific words.
- **Combination support**: All operators can be mixed in complex queries parsed by [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go) and transmitted via the client's `Search` method.

## Frequently Asked Questions

### How do I search for an exact phrase in Hister?

Wrap the phrase in double quotation marks. For example, `"search operators"` ensures the words appear consecutively and in that exact order, rather than matching documents containing both words separately anywhere in the text. The tokenizer in [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go) treats the quoted string as a single indivisible token unit.

### What wildcards does Hister support?

Hister supports the asterisk (`*`) to match zero or more trailing characters and the question mark (`?`) to match exactly one trailing character. These wildcards function as prefix matchers, enabling searches like `doc*` to match *document*, *docs*, and *documentation*.

### How do I exclude terms from search results in Hister?

Prefix the unwanted term with a minus sign (`-excludedTerm`) or use the `NOT` keyword before the term. The query parser in [`server/indexer/query.go`](https://github.com/asciimoo/hister/blob/main/server/indexer/query.go) identifies these negation markers and filters out any documents containing the specified term before returning the final result set to the client.

### Can I combine multiple search operators in a single Hister query?

Yes, phrases, wildcards, and negation can be combined in one query string. For example, `"exact phrase" term* -excluded` uses all three operator types simultaneously. The implementation processes these combined operators sequentially before executing the search against the underlying index.