Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.vscode/
python/__pycache__/
.DS_Store
81 changes: 68 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@

# Khiops Native Interface v11.0.0
# Khiops Native Interface v11.0.1-a.5

This project provides all the basics to use the Khiops Native Interface (KNI): installation and examples.

The purpose of KNI is to allow a deeper integration of Khiops in information systems, by mean of the C programming language, using a shared library (`.dll` in Windows, `.so` in Linux). This relates specially to the problem of model deployment, which otherwise requires the use of input and output data files when using directly the Khiops tool in batch mode. See Khiops Guide for an introduction to dictionary files, dictionaries, database files and deployment.
The purpose of KNI is to allow a deeper integration of Khiops in information systems, by means of the C programming language, using a shared library (`.dll` in Windows, `.so` in Linux). This relates especially to the problem of model deployment, which otherwise requires the use of input and output data files when using directly the Khiops tool in batch mode. See Khiops Guide for an introduction to dictionary files, dictionaries, database files and deployment.

The Khiops deployment API is thus made public through a shared library. Therefore, a Khiops model can be deployed directly from any programming language, such as C, C++, Java, Python, Matlab, etc. This enables real time model deployment without the overhead of temporary data files or launching executables. This is critical for certain applications, such as marketing or targeted advertising on the web..
The Khiops deployment API is thus made public through a shared library. Therefore, a Khiops model can be deployed directly from any programming language, such as C, C++, Java, Python, Matlab, etc. This enables real-time model deployment without the overhead of temporary data files or launching executables. This is critical for certain applications, such as marketing or targeted advertising on the web.
Comment thread
popescu-v marked this conversation as resolved.

All KNI functions are C functions for easy use with other programming languages. They return a positive or zero value in case of success, and a negative error code in case of failure.
All KNI functions are C functions for easy use with other programming languages. The API is compatible with ANSI C (C89/C90) and later standards. They return a positive or zero value in case of success, and a negative error code in case of failure.

See [KhiopsNativeInterface.h](include/KhiopsNativeInterface.h) for a detailed description of KNI functions.

> [!CAUTION]
> The functions are not reentrant (thread-safe): the library can be used simultaneously by several executables, but not simultaneously by several threads in the same executable.
Comment thread
popescu-v marked this conversation as resolved.

## Table of Contents

- [KNI installation](#kni-installation)
- [Windows](#windows)
- [Linux](#linux)
- [Application examples](#application-examples)
- [Example with C](#example-with-c)
- [Building the examples](#building-the-examples)
- [Launch](#launch)
- [Example with Java](#example-with-java)
- [Building the examples](#building-the-examples-1)
- [Launch](#launch-1)
- [Example with Python](#example-with-python)
- [Requirements](#requirements)
- [Scripts](#scripts)
- [Launch](#launch-2)

# KNI installation

## Windows

Download [KNI-11.0.0.zip](https://github.com/KhiopsML/khiops/releases/tag/11.0.0/KNI-11.0.0.zip) and extract it to your machine. Set the environment variable `KNI_HOME` to the extracted directory. This variable is used in the following examples.
Download [KNI-11.0.1-a.5.zip](https://github.com/KhiopsML/khiops/releases/tag/11.0.1/KNI-11.0.1-a.5.zip) and extract it to your machine. Set the environment variable `KNI_HOME` to the extracted directory. This variable is used in the following examples.

## Linux

On Linux, go to the [release page](https://github.com/KhiopsML/khiops/releases/tag/11.0.0/) and download the KNI package. The name of the package begins with **kni** and ends with the **code name** of the OS. The code name is in the release file of the distribution (here, it is "jammy"):
On Linux, go to the [release page](https://github.com/KhiopsML/khiops/releases/tag/11.0.1/) and download the KNI package. The name of the package begins with **kni** and ends with the **code name** of the OS. The code name is in the release file of the distribution (here, it is "jammy"):
```bash
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
Expand All @@ -46,7 +63,7 @@ Download the package according to the code name of your OS and install it with `

Application examples are available in this repository. The main branch corresponds to the latest version of KNI. To explore older versions, switch between branches, which are named after their respective versions.

Both examples in C and Java produce a sample binary `KNIRecodeFile`. It recodes an input file to an output file, using a Khiops dictionary from a dictionary file.
Examples in C, Java, and Python demonstrate how to use KNI. The main example, `KNIRecodeFile`, recodes an input file to an output file using a Khiops dictionary from a dictionary file.

```bash
KNIRecodeFile <Dictionary file> <Dictionary> <Input File> <Output File> [Error file]
Expand All @@ -55,14 +72,14 @@ KNIRecodeFile <Dictionary file> <Dictionary> <Input File> <Output File> [Error f
# The error file may be useful for debugging purposes. It is optional and may be empty.
```

A more complex example (available only in C) is `KNIRecodeMTFiles`, it recodes the input files of multi-table dataset to a single output file.
A more complex example (available in C and Python) is `KNIRecodeMTFiles`, which recodes the input files of a multi-table dataset to a single output file.

```bash
KNIRecodeMTFiles
-d: <input dictionary file> <input dictionary>
[-f: <field separator>
-i: <input file name> [<key index>...]
-s: <secondary data path> < file name> <key index>...
-s: <secondary data path> <file name> <key index>...
-x: <external data root> <external data path> <external file name>
-o: <output file name>
[-e: <error file name>]
Expand All @@ -71,7 +88,7 @@ KNIRecodeMTFiles

# Example with C

The files are located in [cpp directory](cpp/). They allow to build `KNIRecodeFile` and `KNIRecodeMTFiles`.
The files are located in [cpp directory](cpp/). They allow you to build `KNIRecodeFile` and `KNIRecodeMTFiles`.

## Building the examples

Expand Down Expand Up @@ -103,12 +120,12 @@ Recode the "Splice Junction" multi-table dataset using the `SNB_SpliceJunction`

```bash
KNIRecodeMTFiles -d data/ModelingSpliceJunction.kdic SNB_SpliceJunction \
-i .data/SpliceJunction.txt 1 -s DNA data/SpliceJunctionDNA.txt 1 -o R_SpliceJunction.txt
-i data/SpliceJunction.txt 1 -s DNA data/SpliceJunctionDNA.txt 1 -o R_SpliceJunction.txt
```

# Example with Java

The files are located in [java directory](java/). They allow to build `KNIRecodeFile.jar`. This example use [JNA](https://github.com/twall/jna#readme) to make calls to KhiopsNativeInterface.so/dll from Java.
The files are located in [java directory](java/). They allow you to build `KNIRecodeFile.jar`. This example uses [JNA](https://github.com/twall/jna#readme) to make calls to KhiopsNativeInterface.so/dll from Java.

## Building the examples

Expand All @@ -122,7 +139,7 @@ jar cf kni.jar -C java KNI.class -C java KNIRecodeFile.class

## Launch

Recodes the "Iris" dataset from the data directory using the `SNB_Iris` classifier dictionary.
Recode the "Iris" dataset from the data directory using the `SNB_Iris` classifier dictionary.

On Linux:

Expand All @@ -138,3 +155,41 @@ set path=%KNI_HOME%/bin;%path%
java -cp kni.jar;jna.jar KNIRecodeFile data/ModelingIris.kdic SNB_Iris ^
data/Iris.txt R_Iris_java.txt
```

# Example with Python

The files are located in [python directory](python/). They use the `kni` Python package from the pip package `khiops-kni` to call the KhiopsNativeInterface shared library.

## Requirements

- Python 3.10 or later
- The `khiops-kni` package:

```bash
pip install khiops-kni
```

This installs both the `kni` Python module and the KhiopsNativeInterface shared library. No `KNI_HOME` environment variable is needed.

## Scripts

- `KNIRecodeFile.py`: Single-table recoding example
- `KNIRecodeMTFiles.py`: Multi-table recoding example

**API Documentation**: See [Python API Reference](python/docs/kni.md) for detailed documentation of the `kni` module.

## Launch

Recode the "Iris" dataset from the data directory using the `SNB_Iris` classifier dictionary.

```bash
python python/KNIRecodeFile.py data/ModelingIris.kdic SNB_Iris \
data/Iris.txt R_Iris_python.txt
```

For the multi-table "Splice Junction" example:

```bash
python python/KNIRecodeMTFiles.py -d data/ModelingSpliceJunction.kdic SNB_SpliceJunction \
-i data/SpliceJunction.txt 1 -s DNA data/SpliceJunctionDNA.txt 1 -o R_SpliceJunction_python.txt
```
2 changes: 1 addition & 1 deletion cpp/KNIRecodeFile.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Orange. All rights reserved.
// Copyright (c) 2023-2026 Orange. All rights reserved.
// This software is distributed under the BSD 3-Clause-clear License, the text of which is available
// at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

Expand Down
2 changes: 1 addition & 1 deletion cpp/KNIRecodeFile.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Orange. All rights reserved.
// Copyright (c) 2023-2026 Orange. All rights reserved.
// This software is distributed under the BSD 3-Clause-clear License, the text of which is available
// at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

Expand Down
2 changes: 1 addition & 1 deletion cpp/KNIRecodeMTFiles.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Orange. All rights reserved.
// Copyright (c) 2023-2026 Orange. All rights reserved.
// This software is distributed under the BSD 3-Clause-clear License, the text of which is available
// at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

Expand Down
2 changes: 1 addition & 1 deletion cpp/KNIRecodeMTFiles.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Orange. All rights reserved.
// Copyright (c) 2023-2026 Orange. All rights reserved.
// This software is distributed under the BSD 3-Clause-clear License, the text of which is available
// at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

Expand Down
2 changes: 1 addition & 1 deletion include/KhiopsNativeInterface.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023-2025 Orange. All rights reserved.
// Copyright (c) 2023-2026 Orange. All rights reserved.
// This software is distributed under the BSD 3-Clause-clear License, the text of which is available
// at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

Expand Down
141 changes: 141 additions & 0 deletions python/KNIRecodeFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env python3
# Copyright (c) 2023-2026 Orange. All rights reserved.
# This software is distributed under the BSD 3-Clause-clear License, the text of which is available
# at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details.

"""
KNIRecodeFile: Recode an input file to an output file using a Khiops dictionary.

This script demonstrates the use of the Khiops Native Interface (KNI) from Python
to deploy a Khiops model for real-time scoring without temporary files.
"""

import sys
import argparse
from kni import KNI, KNIError


def recode_file(
dictionary_file_name,
dictionary_name,
input_file_name,
output_file_name,
error_file_name="",
):
"""
Recode an input file to an output file using a Khiops dictionary.

Args:
dictionary_file_name: Path to the dictionary file
dictionary_name: Name of the dictionary to use
input_file_name: Path to input file (must have header line)
output_file_name: Path to output file
error_file_name: Optional path to error log file (empty for no logging)

Raises:
KNIError: If any KNI operation fails
FileNotFoundError: If input file is not found
ValueError: If input file is empty or invalid
"""
# Initialize KNI
kni = KNI()

# Set error log file
if error_file_name:
kni.set_log_file_name(error_file_name)

print(f"\nRecode records of {input_file_name} to {output_file_name}")

# Open input and output files
with open(input_file_name, "r", encoding="utf-8") as input_file, open(
output_file_name, "w", encoding="utf-8"
) as output_file:

# Read header line
header_line = input_file.readline().rstrip()
if not header_line:
raise ValueError("Empty input file")

# Open KNI stream
stream_handle = kni.open_stream(
dictionary_file_name, dictionary_name, header_line, "\t"
)

try:
# Process all records
record_number = 0
for line_number, line in enumerate(input_file, start=2):
# Remove trailing whitespace
input_record = line.rstrip()

# Skip empty lines
if not input_record:
continue

# Recode the record
output_record = kni.recode_stream_record(stream_handle, input_record)

# Write output record
output_file.write(f"{output_record}\n")
record_number += 1
finally:
# Close stream
kni.close_stream(stream_handle)

print(f"{record_number} records recoded")


def main():
"""Main entry point for command-line execution."""
parser = argparse.ArgumentParser(
description="Recode an input file to an output file using a Khiops dictionary.",
epilog="The input file must have a header line, describing the structure of all its instances. "
"The input and output files have a tabular format. "
"The error file may be useful for debugging purposes.",
)

parser.add_argument(
"dictionary_file",
help="Path to the dictionary file",
)
parser.add_argument(
"dictionary_name",
help="Name of the dictionary to use",
)
parser.add_argument(
"input_file",
help="Path to input file (must have header line)",
)
parser.add_argument(
"output_file",
help="Path to output file",
)
parser.add_argument(
"error_file",
nargs="?",
default="",
help="Optional path to error log file (empty for no logging)",
)

args = parser.parse_args()

# Execute recoding
try:
recode_file(
args.dictionary_file,
args.dictionary_name,
args.input_file,
args.output_file,
args.error_file,
)
return 0
except FileNotFoundError as e:
print(f"Error: File not found: {e.filename}", file=sys.stderr)
return 1
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1


if __name__ == "__main__":
sys.exit(main())
Loading