---
title: "Searching document text | Nutrient Java SDK"
canonical_url: "https://www.nutrient.io/guides/java/extraction/search-document-text/"
md_url: "https://www.nutrient.io/guides/java/extraction/search-document-text.md"
last_updated: "2026-07-10T00:00:00.000Z"
description: "Search and rank document text passages using Nutrient Java SDK."
---

# Searching document text

A long PDF usually prompts a narrow question: *where does it mention the payment terms?* Reading the whole document back into your application — or running grep after grep — is slow and wasteful. Ranked text search answers the question directly, returning only the few passages that matter, each labeled with the original page it came from.

This sample shows how to search any document with Nutrient Java SDK. The search runs fully offline, with no network calls.

[Download sample](https://www.nutrient.io/downloads/samples/java/search-document-text.zip)

## How Nutrient helps

Nutrient ranks a document with the proven BM-25 algorithm and returns the most relevant passages — each with the page it appears on — instead of the whole file. `Query.createIndex` converts an open `Document` to text and builds a searchable index, so you can ingest a PDF (or DOCX, PPTX, and other supported formats) and then query it with `textSearch` as many times as you like.

The SDK handles:

- Converting the document and tokenizing and ranking its text

- Filtering weak matches so you receive a real answer or nothing — never a list padded with noise

- Optional word-variation matching (stemming), so a query for “organization” also matches “organizations”

- Reporting each result by its original page number

- Returning the result in your chosen format — context windows, plain text, or JSON

## Search a document

Configure the search on a `DocumentSettings`, open the document with it, and build a reusable search index from it with `Query.createIndex`. Then query that index — as many times as you like — by calling `textSearch` on it. Both the document and the index are `AutoCloseable`, so a [try-with-resources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) block releases their resources after processing:

```java

package io.nutrient.Sample;

import io.nutrient.sdk.Document;
import io.nutrient.sdk.settings.DocumentSettings;
import io.nutrient.sdk.Query;
import io.nutrient.sdk.exceptions.NutrientException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class SearchDocumentText {

```

```java

    public static void main(String[] args) {
        // Search configuration travels on the document's settings.
        DocumentSettings settings = new DocumentSettings();
        settings.getSearchSettings().setTopK(3);                  // return the three best passages
        settings.getSearchSettings().setStemmingLanguage("auto"); // detect the language, match word variants

        try (Document document = Document.open("input.pdf", settings);
             Query index = Query.createIndex(document)) {         // convert + build the index once
            String result = index.textSearch("How big is the Earth?");
            String text = (result!= null &&!result.isEmpty())? result : "No relevant matches found.";

            Files.writeString(Paths.get("search-results.txt"), text);
            System.out.println(text);
        } catch (NutrientException e) {
            System.err.println("Error: " + e.getMessage());
        } catch (java.io.IOException e) {
            System.err.println("Error writing results: " + e.getMessage());
        }
    }
}

```

`createIndex` converts the document and builds the index a single time; calling `textSearch` on the returned index then queries it without re-doing either. The query is a natural-language string, matched case-insensitively; stack several relevant terms into one query, because BM-25 rewards rare, on-topic words.

## Understanding the output

Each result leads with the **original document page** and an approximate line, followed by the matching passage:

```text

Page 1, line 3
  We begin at home with Earth, a nearly spherical planet about 13,000 kilometers in diameter...

```

Results are keyed to the page because it’s a stable property of the source document; the line is an approximation — it points into the converted text and can shift between conversions, so use it as a within-page hint rather than an exact coordinate. When nothing clears the relevance floor, `textSearch` returns an empty string — treat that as “no relevant match” rather than an error.

## Tune the search with settings

Every knob lives on `settings.getSearchSettings()`:

- `setTopK` — the maximum number of passages to return (default `8`). Keep it small; you usually want the top one to three.

- `setContextLines` — how many lines of surrounding context to include with each hit (default `5`).

- `setMode` — how aggressively weak matches are filtered: `SearchMode.STRICT`, `SearchMode.BALANCED` (default), or `SearchMode.LENIENT`.

- `setDisplay` — the output format: `SearchDisplay.WINDOWS` (default), `TEXT`, or `JSON` for machine-readable results.

- `setStemmingLanguage` — an ISO 639-1 code (`"en"`, `"fr"`, `"de"`, …) whose word-variation rules to apply, or `"auto"` to detect the document’s language. Empty means exact matching only.

For example, to receive JSON for downstream processing, set the display before building the index:

```text

settings.getSearchSettings().setDisplay(SearchDisplay.JSON);

```

Each JSON result then carries its `page`, `score`, and `text`.

## Searching files, folders, and indexes

Besides a `Document`, you can build an index from a **path** with `Query.createIndex(path, settings)`, then call `textSearch` on it as usual. The path is detected *by content* — not by extension, and with no flag — as one of three kinds:

```text

Query.createIndex("notes.md",    settings).textSearch(query);   // a text or Markdown file
Query.createIndex("./converted", settings).textSearch(query);   // a folder of.md /.txt files
Query.createIndex("report.idx",  settings).textSearch(query);   // a prebuilt index

```

- A **text or Markdown (`.md`/`.txt`) file** is searched line by line; results report **line ranges**.

- A **directory** searches every `.md`/`.txt` file in it as one collection, each result labeled by its source file.

- A **prebuilt index** is loaded as-is, skipping the tokenize-and-rank build step.

Anything else — a PDF, a Word file, a binary — is **rejected** with an error: open those as a `Document` and index them with `Query.createIndex(document)` instead.

### Persisting an index

The index a `Document` builds lives in memory. To reuse it across runs or processes, set the emit-index path when building: the index is written to disk, and you reload it later by passing that file back — no document, no reconversion.

```text

settings.getSearchSettings().setEmitIndexPath("report.idx");
try (Document document = Document.open("input.pdf", settings);
     Query index = Query.createIndex(document)) {   // builds the index AND writes report.idx
}

// Later, in another process — no document needed:
Query.createIndex("report.idx", settings).textSearch(query);

```

A file index built from a `Document` keeps its page information (reports `Page N`); one built from plain text reports line ranges.

## Error handling

Nutrient Java SDK reports failures by throwing a `NutrientException`. Common failure scenarios include:

- The document can’t be opened or read due to a path or permission issue

- The search feature isn’t licensed

In production code, catch `NutrientException`, return a clear error message, and log the failure details for debugging.

## Conclusion

The workflow for ranked document search is:

1. Configure `settings.getSearchSettings()` for the result count, format, and language you need.

2. Open the document with `Document.open(path, settings)`.

3. Build a reusable index with `Query.createIndex(document)`.

4. Query it by calling `textSearch(question)` on the index — as many times as you like.

5. Read the returned passages by page — or set `setDisplay(SearchDisplay.JSON)` for downstream processing.

6. Handle `NutrientException` for robust error recovery.

For the conversion this builds on, refer to the [PDF to Markdown](https://www.nutrient.io/guides/java/conversion/pdf-to-markdown.md) guide.

Download [this ready-to-use sample package](https://www.nutrient.io/downloads/samples/java/search-document-text.zip) to explore document search.
---

## Related pages

- [Applying OCR to a PDF document](/guides/java/extraction/apply-ocr-to-pdf.md)
- [Applying OCR to a PDF page](/guides/java/extraction/apply-ocr-to-pdf-page.md)
- [Classifying documents](/guides/java/extraction/classify-document.md)
- [Generating image descriptions using local AI](/guides/java/extraction/describe-image-with-local-ai.md)
- [Generating image descriptions using OpenAI](/guides/java/extraction/describe-image-with-openai.md)
- [Generating image descriptions using Claude](/guides/java/extraction/describe-image-with-claude.md)
- [Detecting document language](/guides/java/extraction/detect-document-language.md)
- [Extracting data from images using ICR](/guides/java/extraction/extract-data-from-image-icr.md)
- [Extracting data from images using OCR](/guides/java/extraction/extract-data-from-image-ocr.md)
- [Extracting data from specific pages](/guides/java/extraction/extract-data-from-specific-pages.md)
- [Extracting data from images using vision language models](/guides/java/extraction/extract-data-from-image-vlm.md)
- [Extracting form fields from images](/guides/java/extraction/extract-form-fields-from-image.md)
- [Extracting structured data from documents](/guides/java/extraction/extract-structured-data.md)
- [Generating extraction schemas](/guides/java/extraction/generate-extraction-schema.md)
- [Nutrient Java SDK extraction guides](/guides/java/extraction.md)
- [Extracting JSON data from a PDF document](/guides/java/extraction/json-data-extraction.md)
- [Extracting text from PDF documents](/guides/java/extraction/pdf-to-text.md)
- [Labeling form fields with a vision language model](/guides/java/extraction/label-form-fields-with-vlm.md)
- [Reading barcodes with vision extraction](/guides/java/extraction/read-barcodes-with-vision.md)
- [Extracting text from images](/guides/java/extraction/read-text-from-image.md)
- [Speeding up first ICR operation by predownloading models](/guides/java/extraction/speed-up-first-icr-by-downloading-requirements.md)
- [Extracting text from multilingual images](/guides/java/extraction/read-text-from-image-multi-language.md)

