Commit Graph

56 Commits

Author SHA1 Message Date
LangChain4j 8c969bf7e7 updated feature request template 2024-03-20 09:23:06 +01:00
LangChain4j 4a12d62f91 updated bug report template 2024-03-20 09:21:45 +01:00
LangChain4j a172a6134d Azure AI Search: added env vars 2024-03-19 16:23:33 +01:00
LangChain4j 90fe3040b9
released 0.28.0 (#735) 2024-03-11 20:08:55 +01:00
LangChain4j 1acb7a607f
EmbeddingStore (Metadata) Filter API (#610)
## New EmbeddingStore (metadata) `Filter` API
Many embedding stores, such as
[Pinecone](https://docs.pinecone.io/docs/metadata-filtering) and
[Milvus](https://milvus.io/docs/boolean.md) support strict filtering
(think of an SQL "WHERE" clause) during similarity search.
So, if one has an embedding store with movies, for example, one could
search not only for the most semantically similar movies to the given
user query but also apply strict filtering by metadata fields like year,
genre, rating, etc. In this case, the similarity search will be
performed only on those movies that match the filter expression.

Since LangChain4j supports (and abstracts away) many embedding stores,
there needs to be an embedding-store-agnostic way for users to define
the filter expression.

This PR introduces a `Filter` interface, which can represent both simple
(e.g., `type = "documentation"`) and composite (e.g., `type in
("documentation", "tutorial") AND year > 2020`) filter expressions in an
embedding-store-agnostic manner.

`Filter` currently supports the following operations:

- Comparison:
  - `IsEqualTo`
  - `IsNotEqualTo`
  - `IsGreaterThan`
  - `IsGreaterThanOrEqualTo`
  - `IsLessThan`
  - `IsLessThanOrEqualTo`
  - `IsIn`
  - `IsNotIn`

- Logical:
  - `And`
  - `Not`
  - `Or`

These operations are supported by most embedding stores and serve as a
good starting point. However, the list of operations will expand over
time to include other operations (e.g., `Contains`) supported by
embedding stores.

Currently, the DSL looks like this:
```java
Filter onlyDocs = metadataKey("type").isEqualTo("documentation");

Filter docsAndTutorialsAfter2020 = metadataKey("type").isIn("documentation", "tutorial").and(metadataKey("year").isGreaterThan(2020));
// or
Filter docsAndTutorialsAfter2020 = and(
    metadataKey("type").isIn("documentation", "tutorial"),
    metadataKey("year").isGreaterThan(2020)
);
```

## Filter expression as a `String`
Filter expression can also be specified as a `String`. This might be
necessary, for example, if the filter expression is generated
dynamically by the application or by the LLM (as in [self
querying](https://python.langchain.com/docs/modules/data_connection/retrievers/self_query/)).

This PR introduces a `FilterParser` interface with a simple `Filter
parse(String)` API, allowing for future support of multiple syntaxes (if
this will be required).

For the out-of-the-box filter syntax, ANSI SQL's `WHERE` clause is
proposed as a suitable candidate for several reasons:
- SQL is well-known among Java developers
- There is extensive tooling available for SQL (e.g., parsers)
- LLMs are pretty good at generating valid SQL, as there are tons of SQL
queries on the internet, which are included in the LLM training
datasets. There are also specialized LLMs that are trained for
text-to-SQL task, such as [SQLCoder](https://huggingface.co/defog).

The downside is that SQL's `WHERE` clause might not support all
operations and data types that could be supported in the future by
various embedding stores. In such case, we could extend it to a superset
of ANSI SQL `WHERE` syntax and/or provide an option to express filters
in the native syntax of the store.

An out-of-the-box implementation of the SQL `FilterParser` is provided
as a `SqlFilterParser` in a separate module
`langchain4j-embedding-store-filter-parser-sql`, using
[JSqlParser](https://github.com/JSQLParser/JSqlParser) under the hood.

`SqlFilterParser` can parse SQL "SELECT" (or just "WHERE" clause)
statement into a `Filter` object:
- `SELECT * FROM fake_table WHERE userId = '123-456'` ->
`metadataKey("userId").isEqualTo("123-456")`
- `userId = '123-456'`  ->  `metadataKey("userId").isEqualTo("123-456")`

It can also resolve `CURDATE()` and
`CURRENT_DATE`/`CURRENT_TIME`/`CURRENT_TIMESTAMP`:
`SELECT * FROM fake_table WHERE year = EXTRACT(YEAR FROM CURRENT_DATE`
-> `metadataKey("year").isEqualTo(LocalDate.now().getYear())`

## Changes in `Metadata` API
Until now, `Metadata` supported only `String` values. This PR expands
the list of supported value types to `Integer`, `Long`, `Float` and
`Double`. In the future, more types may be added (if needed).
The method `String get(String key)` will be deprecated later in favor
of:
- `String getString(String key)`
- `Integer getInteger(String key)`
- `Long getLong(String key)`
- etc

New overloaded `put(key, value)` methods are introduced to support more
value types:
- `put(String key, int value)`
- `put(String key, long value)`
- etc

## Changes in `EmbeddingStore` API
New method `search` is added that will become the main entry point for
search in the future. All `findRelevant` methods will be deprecated
later.
New `search` method accepts `EmbeddingSearchRequest` and returns
`EmbeddingSearchResult`.
`EmbeddingSearchRequest` contains all search criteria (e.g.
`maxResults`, `minScore`), including new `Filter`.
`EmbeddingSearchResult` contains a list of `EmbeddingMatch`.
```java
EmbeddingSearchResult search(EmbeddingSearchRequest request);
```

## Changes in `EmbeddingStoreContentRetriever` API
`EmbeddingStoreContentRetriever` can now be configured with a static
`filter` as well as dynamic `dynamicMaxResults`, `dynamicMinScore` and
`dynamicFilter` in the builder:
```java
ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                ...
                .maxResults(3)
                // or
                .dynamicMaxResults(query -> 3) // You can define maxResults dynamically. The value could, for example, depend on the query or the user associated with the query.
                ...
                .minScore(0.3)
                // or
                .dynamicMinScore(query -> 0.3)
                ...
                .filter(metadataKey("userId").isEqualTo("123-456")) // Assuming your TextSegments contain Metadata with key "userId"
                // or
                .dynamicFilter(query -> metadataKey("userId").isEqualTo(query.metadata().chatMemoryId().toString()))
                ...
                .build();
```
So now you can define `maxResults`, `minScore` and `filter` both
statically and dynamically (they can depend on the query, user, etc.).
These values will be propagated to the underlying `EmbeddingStore`.

##
["Self-querying"](https://python.langchain.com/docs/modules/data_connection/retrievers/self_query/)
This PR also introduces `LanguageModelSqlFilterBuilder` in
`langchain4j-embedding-store-filter-parser-sql` module which can be used
with `EmbeddingStoreContentRetriever`'s `dynamicFilter` to automatically
build a `Filter` object from the `Query` using language model and
`SqlFilterParser`.

For example:
```java
TextSegment groundhogDay = TextSegment.from("Groundhog Day", new Metadata().put("genre", "comedy").put("year", 1993));
TextSegment forrestGump = TextSegment.from("Forrest Gump", new Metadata().put("genre", "drama").put("year", 1994));
TextSegment dieHard = TextSegment.from("Die Hard", new Metadata().put("genre", "action").put("year", 1998));

// describe metadata keys as if they were columns in the SQL table
TableDefinition tableDefinition = TableDefinition.builder()
                .name("movies")
                .addColumn("genre", "VARCHAR", "one of [comedy, drama, action]")
                .addColumn("year", "INT")
                .build();

LanguageModelSqlFilterBuilder sqlFilterBuilder = new LanguageModelSqlFilterBuilder(model, tableDefinition);

ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .dynamicFilter(sqlFilterBuilder::build)
                .build();

String answer = assistant.answer("Recommend me a good drama from 90s"); // Forrest Gump
```

## Which embedding store integrations will support `Filter`?
In the long run, all (provided the embedding store itself supports it).
In the first iteration, I aim to add support to just a few:
- `InMemoryEmbeddingStore`
- Elasticsearch
- Milvus

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Introduced filters for checking key's value existence in a collection
for improved data handling.
- **Enhancements**
- Updated `InMemoryEmbeddingStoreTest` to extend a different class for
improved testing coverage and added a new test method.
- **Refactor**
- Made minor formatting adjustments in the assertion block for better
readability.
- **Documentation**
  - Updated class hierarchy information for clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-03-08 17:06:58 +01:00
LangChain4j fdbfd873f7 Upgrade langchain4j-opensearch to use latest version of opensearch-java client which enables Java 8 support (#663) 2024-03-08 08:44:58 +01:00
LangChain4j 1118a1ac1a Upgrade langchain4j-opensearch to use latest version of opensearch-java client which enables Java 8 support (#663) 2024-03-05 18:46:59 +01:00
LangChain4j 9d4234342e
Fixed snapshot release (#650) 2024-02-21 07:56:24 +01:00
LangChain4j c1462c087f
release 0.27.1 (#621) 2024-02-09 15:00:42 +01:00
LangChain4j a22d297104
Release 0.27.0 (#615) 2024-02-09 08:00:34 +01:00
LangChain4j 8a40c0c5d3 release cassandra 2024-02-08 15:57:06 +01:00
Cedrick Lunven cd006b166c
Rework support of AstraDB and Cassandra (#548)
In the Datastax Astra DB saas solution, a new way to integrate with
vector databases has been introduced: using an HTTP APi instead of the
Cassandra Cluster. It is called the DataAPI and use the MongoDB
principles with collections.

The pull request includes the following:

### Update on previous implementations

- Previous implementations of embedding stores have been grouped in a
single `CassandraEmbeddingStore`. It can be instantiated for Astra or
OSS Cassandra based on 2 different constructor builders but everything
else is the same.

- Previous implementations of chat memory stores have been grouped in a
single `CassandraChatMemoryStore`. It can be instantiated for Astra or
OSS Cassandra based on 2 different constructor builders but everything
else is the same.

- Integration test for OSS Cassandra now using test containers (as
Cassandra 5-alpha2 image is out)

- Usage
```java
// Using with Astra (Cassandra AAS in the cloud)
CassandraEmbeddingStore.builderAstra()
  .token(token)
  .databaseId(dbId)
  .databaseRegion(TEST_REGION)
  .keyspace(KEYSPACE)
  .table(TEST_INDEX)
  .dimension(11)
  .metric(CassandraSimilarityMetric.COSINE)
  .build();

// Using OSS Cassandra
CassandraEmbeddingStore.builder()
  .contactPoints(Arrays.asList(contactPoint.getHostName()))
  .port(contactPoint.getPort())
  .localDataCenter(DATACENTER)
  .keyspace(KEYSPACE)
  .table(TEST_INDEX)
  .dimension(11)
  .metric(CassandraSimilarityMetric.COSINE)
  .build();
```

-Adding jdk11 in the pom

```
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
```

- introducing `insertMany()`,  distributed to all bulk loading

- Extending the variables `EmbeddingStoreIT`

- Using `MessageWindowChatMemory` for the tests.
2024-02-08 15:54:53 +01:00
LangChain4j 732c18f8a4 Infinispan: cosmetics 2024-02-08 12:03:55 +01:00
LangChain4j 3de8e358d8 Infinispan: cosmetics 2024-02-08 12:01:32 +01:00
LangChain4j 1e6f5bc316 MongoDB: added javadoc, updated IT to use env vars 2024-02-08 10:38:59 +01:00
Amith Koujalgi 31f0da6e94
Docs updates (#599)
- Updated docs GH workflow to build and publish javadoc alongside of
docs directory. This would make the docs available at
https://langchain4j.github.io/langchain4j and javadoc at
https://langchain4j.github.io/langchain4j/apidocs/index.html
- Updated javadoc build command in docs GH workflow to do a full project
build (that includes all modules and no exclusions).
- Updated javadoc build in docs GH workflow to run with Java 21 version.

This is in reference to
https://github.com/langchain4j/langchain4j/discussions/596

---------

Co-authored-by: Lize Raes <49833622+LizeRaes@users.noreply.github.com>
2024-02-06 11:13:41 +01:00
LangChain4j e1c02b6f52 Explicitly skip Ollama, Vearch and VertexAI Gemini ITs during snapshot release 2024-02-05 14:14:48 +01:00
LangChain4j 55bcd5cf27
Adding NomicEmbeddingModel (#592)
An integration with [Nomic Atlas's Text Embeddings
API](https://docs.nomic.ai/reference/endpoints/nomic-embed-text).
2024-02-05 08:39:28 +01:00
Julien Perrochet 4cef820c9f
[ci] publish snapshots with every commit to main (#16)
Adds a workflow for publishing a snapshot to sonatype with each commit
to main.
2024-01-31 10:51:09 +01:00
LangChain4j 3958e01738
release 0.26.1 (#570) 2024-01-30 16:11:21 +01:00
LangChain4j a8ad9e48d9
Automate release (#562) 2024-01-30 07:20:20 +01:00
Lize Raes 88153721aa
action to build and publish javadoc to pages (#504)
Adds the following:

 * add maven plugin for generating javadoc 
 * action to build and publish javadoc to pages
 * update javadoc link in docusaurus
2024-01-12 12:50:44 +01:00
Amith Koujalgi 7e42166109
Updated Docs (#500)
- Updated subpage 0 to `Overview` and made it the landing page upon
clicking `Tutorials` from the horizontal/navigation/top bar.
- Set up GitHub action to build and publish the docs to the GitHub pages
on release. [Preview](https://amithkoujalgi.github.io/langchain4j/) of
the docs on GitHub pages. This action/workflow can also be triggered
manually.
- Added content to `/integrations/language-models/ollama`

PS:
If GitHub pages has been enabled in the repository, the repo admin
should be able to run the new GitHub workflow/action in the Actions tab
and after the completion of the workflow, the docs should be available
in the link provided by GitHub (or a specified custom domain).
2024-01-11 09:04:38 +01:00
LangChain4j 2a5308b794 released 0.25.0 2023-12-22 18:02:04 +01:00
LangChain4j 9cf5826fc2
rename langchain4j-graal module (#405) 2023-12-22 13:11:57 +01:00
Giuseppe Villani c35a4e22ea
Fixes #241: Added support for Neo4j Vector Index (#282)
Fixes #241: Added support for Neo4j Vector Index

This commit brings support for Neo4j graph database in general, and uses
the vector index functionality, generally available since version 5.13.

Mostly aligned with the existing WeaviateEmbeddingStoreImpl
implementation and tests.
The tests have some additional Neo4j node assertion to check that the
nodes involved are correctly created.

The module creates indexes, i.e. `"CALL
db.index.vector.createNodeIndex(<indexName>, <label>,
<embeddingProperty>, <dimension>, <distanceType>)"`, if needed, for the
vector search .

The required configurations are:
- the Neo4j index dimension parameter
- the Neo4j Java Driver connection instance
- as an alternative to the Neo4j Java Driver, we can create a
`Neo4jEmbeddingStore.builder().withBasicAuth(<url>, <username>,
<password>)`, which will create a Driver connection instance under the
hood

It is possible to customize, via the builder:
- the index name (with default `langchain-embedding-index`)
- the Neo4j node label  (with default `Document`)
- the Neo4j property key which save the embeddings (with default
`embeddingProp`)
- the Neo4j index distanceType parameter
- the metadata prefix (with default `metadata.`)
- the text property key (with default `text`), which store the text
field of the `TextSegment.java`


Created an example PR as well, on `langchain4j-examples` repo:
https://github.com/langchain4j/langchain4j-examples/pull/23
2023-12-18 18:04:05 +01:00
LangChain4j b8f33aae67 Revert "excluded neo4j module from java 8 and 11 builds"
This reverts commit f5039b6eea.
2023-12-18 10:08:50 +01:00
LangChain4j f5039b6eea
excluded neo4j module from java 8 and 11 builds 2023-12-18 09:31:10 +01:00
Julien Dubois 52fdbaf6df
Update GitHub Actions versions (#357)
In the GitHub Actions workflow:

- Update actions/checkout to the latest version
- Update actions/setup-java to the latest version (Java 21 already works
but is undocumented, the next version it will be thanks to
https://github.com/actions/setup-java/pull/538 😀)
2023-12-15 15:24:22 +01:00
Julien Dubois 3c0943d38b
Support Java 21 (#336)
This PR is to fix #335
2023-12-12 19:16:41 +01:00
shalk(xiao kun) b2f358c926
enable langchain4j-graal build in workflow (#333) 2023-12-08 10:30:36 +01:00
deep-learning-dynamo 06ada5310d disabled jdk17 build temporarily 2023-11-24 12:25:05 +01:00
LangChain4j ba7fabaa50
graal: cleanup (#297) 2023-11-19 12:59:24 +01:00
LangChain4j ff998ac82d
build most modules with jdk 8 (#295)
Since we target java 8, CI build was updated to run most modules using
java 8, then modules requiring java 11 separately with java 11
2023-11-18 15:07:11 +01:00
deep-learning-dynamo 21dfc8b317 released 0.24.0 2023-11-12 18:58:31 +01:00
deep-learning-dynamo eef1796963 fixing build 2023-10-09 13:09:25 +02:00
deep-learning-dynamo 315eab8641 released 0.23.0 2023-09-29 14:27:51 +02:00
deep-learning-dynamo ef8f04015b Removed dynamic loading from AstraDB/Cassandra 2023-09-27 17:11:01 +02:00
Cedrick Lunven c632322493
Cassandra and Astra (dbaas) as VectorStore and ChatMemoryStore (#162)
#### Context

Apache Cassandra is a popular open-source database created back in 2008.
This year with
[CEP30](https://cwiki.apache.org/confluence/display/CASSANDRA/CEP-30%3A+Approximate+Nearest+Neighbor%28ANN%29+Vector+Search+via+Storage-Attached+Indexes)
support for vector and similarity searches have been introduced.
Cassandra is very fast in read and write and is used as a cache by many
companies, it as an opportunity to implement the ChatMemoryStore. This
feature is expected for Cassandra 5 at the end of the year but some
docker images are already available.

DataStax AstraDb is a distribution of Apache Cassandra available as Saas
providing a free tier (free forever) of 80 millions queries/month.
[Registration](https://astra.datastax.com). The vector capability is
there production ready.

#### Data Modelling

With the proper data model in Cassandra we can perform both similarity
search, keyword search, metadata search.

```sql
CREATE TABLE sample_vector_table (
    row_id text PRIMARY KEY,
    attributes_blob text,
    body_blob text,
    metadata_s map<text, text>,
    vector vector<float, 1536>
);
```

#### Implementation Throughts

- The **configuration** to connect to Astra and Cassandra are not
exactly the same so 2 different classes with associated builder are
provided:
[Astra](https://github.com/clun/langchain4j/blob/main/langchain4j/src/main/java/dev/langchain4j/store/embedding/cassandra/AstraDbEmbeddingConfiguration.java)
and [OSS
Cassandra](https://github.com/clun/langchain4j/blob/main/langchain4j/src/main/java/dev/langchain4j/store/embedding/cassandra/CassandraEmbeddingConfiguration.java).
A couple of fields are mutualized but creating a superclass to inherit
from lead to the use of Lombok `@SuperBuilder` and the Javadoc was not
able to found out what to do.

- Instead of passing a large number of arguments like other stores I
prefer to wrap them as a bean. With this trick you can add or remove
attributes, make then optional or mandatory at will. If you need to add
a new attribute in the configuration you do not have to change the
implementation of `XXXStore` and `XXXStoreImpl`

- I create an
[AstractEmbeddedStore<T>](https://github.com/clun/langchain4j/blob/main/langchain4j/src/main/java/dev/langchain4j/store/embedding/AbstractEmbeddingStore.java)
that could very well become the super class for any store. It handles
the different call of the real concrete implementation. (_delegate
pattern_). Some default implementation can be implemented

```java
/**
 * Add a list of embeddings to the store.
 *
 * @param embeddings
 *      list of embeddings (hold vector)
 * @return
 *      list of ids
*/
@Override
public List<String> addAll(List<Embedding> embeddings) {
   Objects.requireNonNull(embeddings, "embeddings must not be null");
   return embeddings.stream().map(this::add).collect(Collectors.toList());
}
```

The only method to implement at the Store level is:

```java
/**
* Initialize the concrete implementation.
* @return create implementation class for the store
*/
protected abstract EmbeddingStore<T> loadImplementation()
throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
       IllegalAccessException, InvocationTargetException;
```

-
[CassandraEmbeddedStore](https://github.com/clun/langchain4j/blob/main/langchain4j/src/main/java/dev/langchain4j/store/embedding/cassandra/CassandraEmbeddingStore.java#L30)
proposes 2 constructors, one could override the implementation class if
they want (extension point)

#### Tests

- Test classes are provided including some long form examples based on
classed found in `langchain4j-examples` but test are disabled.

- To start a local cassandra use docker and the
[docker-compose](https://github.com/clun/langchain4j/blob/main/langchain4j-cassandra/src/test/resources/docker-compose.yml)

```
docker compose up -d
```

- To run Test with Astra signin with your github account, create a token
(api Key) with role `Organization Administrator` following this
[procedure](https://awesome-astra.github.io/docs/pages/astra/create-token/#c-procedure)

<img width="926" alt="Screenshot 2023-09-06 at 18 14 12"
src="https://github.com/langchain4j/langchain4j/assets/726536/dfd2d9e5-09c9-4504-bfaa-31cfd87704a1">

- Pick the full value of the `token` from the json

<img width="713" alt="Screenshot 2023-09-06 at 18 15 53"
src="https://github.com/langchain4j/langchain4j/assets/726536/1be56234-dd98-4f59-af71-03df42ed6997">

- Create the environment variable `ASTRA_DB_APPLICATION_TOKEN`

```console
export ASTRA_DB_APPLICATION_TOKEN=AstraCS:....<your_token>
```
2023-09-27 15:50:04 +02:00
deep-learning-dynamo c1cc5be1c7 released 0.22.0 2023-08-29 19:21:56 +02:00
deep-learning-dynamo db1f236ed2 released 0.21.0 2023-08-19 15:57:39 +02:00
deep-learning-dynamo d7b96ca9a6 released 0.20.0 2023-08-14 00:44:07 +02:00
deep-learning-dynamo 1541f214c1 released 0.19.0 2023-08-10 14:34:21 +02:00
Julien Perrochet 5cb371d7bf
[ci] let the compliance check run on all modules (#75)
Some leftovers from an earlier (and now incorrect) CI configuration.

Modules that don't need to comply with the licenses need to deactivate
the relevant plugin on a case-by-case basis.
2023-08-06 21:22:26 +02:00
deep-learning-dynamo d4fca658c1 released 0.18.0 2023-07-26 21:19:24 +02:00
LangChain4j 540741c8e5
Temporarily disabled in-process embedding model tests (#48)
We are out of free Git LFS quota
2023-07-24 19:52:30 +02:00
LangChain4j 529ef6b647
Added in-process embedding models (#41)
- all-minilm-l6-v2
- all-minilm-l6-v2-q
- e5-small-v2
- e5-small-v2-q

The idea is to give users an option to embed documents/texts in the same
Java process without any external dependencies.
ONNX Runtime is used to run models inside JVM.
Each model resides in it's own maven module (inside the jar).
2023-07-23 19:05:13 +02:00
deep-learning-dynamo 1976560aeb released 0.16.0 2023-07-18 10:49:43 +02:00
deep-learning-dynamo e439f96466 released 0.15.0 2023-07-18 00:13:08 +02:00
deep-learning-dynamo 14185653c7 released 0.14.0 2023-07-16 12:15:31 +02:00