<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Stages on Lucille</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/</link><description>Recent content in Stages on Lucille</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 16 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/index.xml" rel="self" type="application/rss+xml"/><item><title>All Stages</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/all-stages/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/all-stages/</guid><description>&lt;p&gt;This page lists all Stages available in &lt;code&gt;lucille-core&lt;/code&gt; and as optional plugin modules.&lt;/p&gt;
&lt;p&gt;All stages share common configuration parameters:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Parameter&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;class&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;Required.&lt;/strong&gt; The fully qualified class name of the Stage.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Optional display name used in logging and metrics.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;conditions&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Optional list of conditions controlling when the Stage executes.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;conditionPolicy&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;any&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;all&amp;quot;&lt;/code&gt; (default: &lt;code&gt;&amp;quot;all&amp;quot;&lt;/code&gt;).&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="field-manipulation"&gt;Field Manipulation&lt;/h2&gt;
&lt;h3 id="copyfields"&gt;CopyFields&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;com.kmwllc.lucille.stage.CopyFields&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Copies one or more source fields to destination fields.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Parameter&lt;/th&gt;
 &lt;th&gt;Type&lt;/th&gt;
 &lt;th&gt;Required&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;source&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List&amp;lt;String&amp;gt;&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;Source field names.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dest&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List&amp;lt;String&amp;gt;&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;Destination field names (parallel to &lt;code&gt;source&lt;/code&gt;).&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;updateMode&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;overwrite&lt;/code&gt;, &lt;code&gt;append&lt;/code&gt;, or &lt;code&gt;skip&lt;/code&gt;. Default: &lt;code&gt;overwrite&lt;/code&gt;.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-hocon" data-lang="hocon"&gt;{ class: &amp;#34;com.kmwllc.lucille.stage.CopyFields&amp;#34;, source: [&amp;#34;title&amp;#34;], dest: [&amp;#34;title_copy&amp;#34;] }
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id="renamefields"&gt;RenameFields&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;com.kmwllc.lucille.stage.RenameFields&lt;/code&gt;&lt;/p&gt;</description></item><item><title>ChunkText</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/chunk_text/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/chunk_text/</guid><description>&lt;p&gt;The &lt;code&gt;ChunkText&lt;/code&gt; Stage splits a long text field into smaller, optionally overlapping segments. Each segment is emitted as a &lt;strong&gt;child document&lt;/strong&gt; that flows independently through all downstream stages and is indexed as its own record. This is the foundation of retrieval-augmented generation (RAG) pipelines in Lucille.&lt;/p&gt;
&lt;h2 id="configuration"&gt;Configuration&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-hocon" data-lang="hocon"&gt;{
 class: &amp;#34;com.kmwllc.lucille.stage.ChunkText&amp;#34;
 source: &amp;#34;body&amp;#34;
 dest: &amp;#34;text&amp;#34;
 chunkingMethod: &amp;#34;sentence&amp;#34;
 chunksToMerge: 5
 chunksToOverlap: 1
 cleanChunks: true
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="configuration-parameters"&gt;Configuration Parameters&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Parameter&lt;/th&gt;
 &lt;th&gt;Type&lt;/th&gt;
 &lt;th&gt;Required&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;source&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Field containing the text to chunk.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dest&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Field name for chunk content in child docs. Default: &lt;code&gt;text&lt;/code&gt;.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;chunkingMethod&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Chunking strategy. Default: &lt;code&gt;sentence&lt;/code&gt;. See below.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;regex&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;Required for &lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Regex pattern to split on.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;lengthToSplit&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;Required for &lt;code&gt;fixed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of characters per chunk.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;chunksToMerge&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;How many initial chunks to merge into one final chunk. Default: &lt;code&gt;1&lt;/code&gt; (no merging).&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;chunksToOverlap&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Number of chunks from the previous final chunk to prepend to the current one.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;overlapPercentage&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Percentage of the current chunk&amp;rsquo;s characters to add from its neighbours. Default: &lt;code&gt;0&lt;/code&gt;.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;characterLimit&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Hard maximum character count for a final chunk after all merging.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;preMergeMinChunkLen&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Initial chunks shorter than this are appended to a neighbour before merging.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;preMergeMaxChunkLen&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Integer&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Initial chunks longer than this are truncated before merging.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;cleanChunks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Boolean&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Remove internal newlines and trim whitespace from each chunk. Default: &lt;code&gt;false&lt;/code&gt;.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="chunking-methods"&gt;Chunking Methods&lt;/h2&gt;
&lt;h3 id="sentence-default"&gt;&lt;code&gt;sentence&lt;/code&gt; (default)&lt;/h3&gt;
&lt;p&gt;Detects sentence boundaries using an Apache OpenNLP sentence detector. This produces semantically coherent chunks. Best used with &lt;code&gt;chunksToMerge&lt;/code&gt; to combine a few sentences into each final chunk.&lt;/p&gt;</description></item><item><title>PromptOllama</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/prompt_ollama/</link><pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/prompt_ollama/</guid><description>&lt;p&gt;What if you could just, actually, put an LLM on everything?&lt;/p&gt;
&lt;h3 id="ollama"&gt;Ollama&lt;/h3&gt;
&lt;p&gt;Ollama allows you to run a variety of Large Language Models (LLMs) with minimal setup. You can also create custom models
using Modelfiles and system prompts.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;PromptOllama&lt;/code&gt; Stage allows you to connect to a running instance of Ollama Server, which communicates with an LLM through a simple API.
The Stage sends part (or all) of a Document to the LLM for generic enrichment. You&amp;rsquo;ll want to create a custom model (with a Modelfile)
or provide a System Prompt in the Stage Config that is tailored to your pipeline.&lt;/p&gt;</description></item><item><title>QueryOpensearch</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/query_opensearch/</link><pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/query_opensearch/</guid><description>&lt;p&gt;&lt;code&gt;com.kmwllc.lucille.stage.QueryOpensearch&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="opensearch-templates"&gt;OpenSearch Templates&lt;/h3&gt;
&lt;p&gt;You can use templates in OpenSearch to repeatedly run a certain query using different parameters. For example,
if we have an index full of parks, and we want to search for a certain park, we might use a template like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#000;font-weight:bold"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#000;font-weight:bold"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#000;font-weight:bold"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;match_phrase&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#000;font-weight:bold"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;park_name&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;{{park_to_search}}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#000;font-weight:bold"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#000;font-weight:bold"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#000;font-weight:bold"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#000;font-weight:bold"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Opensearch, you could then call this template (providing it &lt;code&gt;park_to_search&lt;/code&gt;) instead of writing out the full query each time you want to search.&lt;/p&gt;</description></item><item><title>EmbeddedPython</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/embedded_python/</link><pubDate>Tue, 16 Dec 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/embedded_python/</guid><description>&lt;h3 id="why-use-it"&gt;Why Use It?&lt;/h3&gt;
&lt;p&gt;EmbeddedPython executes per-document Python code inside the Lucille JVM using &lt;a href="https://www.graalvm.org/python/"&gt;GraalPy&lt;/a&gt;. Instead of returning a JSON object, your script mutates the current document directly through a Python-friendly proxy bound as doc (and the raw Java document as rawDoc). This avoids ports, subprocesses, venvs, and per-document JSON round trips.&lt;/p&gt;
&lt;h3 id="when-to-use-it"&gt;When To Use It&lt;/h3&gt;
&lt;p&gt;Use EmbeddedPython when you need one or more of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimal operational overhead (ports, subprocess lifecycle, venv creation, pip installs).&lt;/li&gt;
&lt;li&gt;No use of any external Python libraries or native dependencies that require a real Python environment.&lt;/li&gt;
&lt;li&gt;Lightweight field enrichment/transformation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use-externalpython-instead"&gt;When To Use ExternalPython Instead&lt;/h3&gt;
&lt;p&gt;Avoid EmbeddedPython and use ExternalPython when you need one or more of the following:&lt;/p&gt;</description></item><item><title>ExternalPython</title><link>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/external_python/</link><pubDate>Tue, 16 Dec 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-pre-release/ingest-design/stages/external_python/</guid><description>&lt;h3 id="why-use-it"&gt;Why Use It?&lt;/h3&gt;
&lt;p&gt;ExternalPython delegates per-document processing to an external Python process using &lt;a href="https://www.py4j.org/"&gt;Py4J&lt;/a&gt;. Lucille serializes the Document into a request, calls a Python function, receives a JSON response, and applies that response back onto the document.&lt;/p&gt;
&lt;h3 id="when-to-use-it"&gt;When To Use It&lt;/h3&gt;
&lt;p&gt;Use ExternalPython when you need one or more of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real Python compatibility (including packages with native dependencies).&lt;/li&gt;
&lt;li&gt;Dependency management via a requirements.txt installed into a managed venv.&lt;/li&gt;
&lt;li&gt;Process isolation apart from the JVM.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use-embeddedpython-instead"&gt;When To Use EmbeddedPython Instead&lt;/h3&gt;
&lt;p&gt;Avoid ExternalPython and use EmbeddedPython when you need one or more of the following:&lt;/p&gt;</description></item></channel></rss>