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
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fluent API.
| [SQL (JDBC)]({{ site.baseurl }}/tutorials/sql) | `{{ site.group_id }}:querydsl-sql` |
| [R2DBC (Reactive SQL)]({{ site.baseurl }}/tutorials/r2dbc) | `{{ site.group_id }}:querydsl-r2dbc` |
| [MongoDB]({{ site.baseurl }}/tutorials/mongodb) | `{{ site.group_id }}:querydsl-mongodb` |
| [Lucene]({{ site.baseurl }}/tutorials/lucene) | `{{ site.group_id }}:querydsl-lucene9` / `querydsl-lucene10` |
| [Collections]({{ site.baseurl }}/tutorials/collections) | `{{ site.group_id }}:querydsl-collections` |
| [Spatial]({{ site.baseurl }}/tutorials/spatial) | `{{ site.group_id }}:querydsl-sql-spatial` |
| [Kotlin Extensions]({{ site.baseurl }}/tutorials/kotlin) | `{{ site.group_id }}:querydsl-kotlin` |
Expand Down
2 changes: 1 addition & 1 deletion docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ construction faster and safer.

HQL for Hibernate was the first target language for Querydsl. Today the
framework supports **JPA**, **SQL (JDBC)**, **R2DBC**, **MongoDB**,
**Collections**, **Spatial**, **Kotlin**, and **Scala** as backends.
**Lucene**, **Collections**, **Spatial**, **Kotlin**, and **Scala** as backends.

If you are new to database access in Java,
[this guide](https://www.marcobehler.com/guides/a-guide-to-accessing-databases-in-java)
Expand Down
8 changes: 5 additions & 3 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ The following modules have been removed from this fork:
| Module | Reason | Alternative |
|:-------|:-------|:------------|
| `querydsl-jdo` | JDO usage has declined significantly | Use JPA instead |
| `querydsl-lucene3` | Lucene 3 is EOL | Use Lucene/Elasticsearch client directly |
| `querydsl-lucene4` | Lucene 4 is EOL | Use Lucene/Elasticsearch client directly |
| `querydsl-lucene5` | Lucene integration is rarely used | Use Lucene/Elasticsearch client directly |
| `querydsl-lucene3` | Lucene 3 is EOL | Use `querydsl-lucene9` or `querydsl-lucene10` |
| `querydsl-lucene4` | Lucene 4 is EOL | Use `querydsl-lucene9` or `querydsl-lucene10` |
| `querydsl-lucene5` | Lucene 5 is EOL | Use `querydsl-lucene9` or `querydsl-lucene10` |
| `querydsl-hibernate-search` | Hibernate Search has its own query DSL | Use Hibernate Search API directly |

If you depend on any of these modules, you have two options:
Expand All @@ -174,6 +174,8 @@ If you depend on any of these modules, you have two options:
| Module | Description |
|:-------|:------------|
| [`querydsl-r2dbc`]({{ site.baseurl }}/tutorials/r2dbc) | Reactive, non-blocking database access via R2DBC and Project Reactor |
| [`querydsl-lucene9`]({{ site.baseurl }}/tutorials/lucene) | Lucene 9 integration (Java 17+), replacing the old lucene3/4/5 modules |
| [`querydsl-lucene10`]({{ site.baseurl }}/tutorials/lucene) | Lucene 10 integration (Java 21+) |
| [`querydsl-kotlin`]({{ site.baseurl }}/tutorials/kotlin) | Kotlin extension functions — use `+`, `-`, `*`, `/`, `%` operators on expressions |

## Step-by-Step Migration
Expand Down
212 changes: 212 additions & 0 deletions docs/tutorials/lucene.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
layout: default
title: Querying Lucene
parent: Tutorials
nav_order: 6
---

# Querying Lucene

This chapter describes the querying functionality of the Lucene modules.

## Maven Integration

Two modules are available depending on your Lucene version:

**Lucene 9** (Java 17+):

```xml
<dependency>
<groupId>{{ site.group_id }}</groupId>
<artifactId>querydsl-lucene9</artifactId>
<version>{{ site.querydsl_version }}</version>
</dependency>
```

**Lucene 10** (Java 21+):

```xml
<dependency>
<groupId>{{ site.group_id }}</groupId>
<artifactId>querydsl-lucene10</artifactId>
<version>{{ site.querydsl_version }}</version>
</dependency>
```

Both modules provide the same API. The examples below use the `com.querydsl.lucene9`
package — replace with `com.querydsl.lucene10` if you are on Lucene 10.

## Creating the Query Types

Since Lucene has no schema, query types are created manually. For a document
with `year` and `title` fields the query type looks like this:

```java
public class QDocument extends EntityPathBase<Document> {
private static final long serialVersionUID = -4872833626508344081L;

public QDocument(String var) {
super(Document.class, PathMetadataFactory.forVariable(var));
}

public final StringPath year = createString("year");

public final StringPath title = createString("title");
}
```

`QDocument` represents a Lucene document with the fields `year` and `title`.

Code generation is not available for Lucene since no schema data is available.

## Querying

Querying with Querydsl Lucene is straightforward:

```java
QDocument doc = new QDocument("doc");

IndexSearcher searcher = new IndexSearcher(index);
LuceneQuery query = new LuceneQuery(searcher);
List<Document> documents = query
.where(doc.year.between("1800", "2000").and(doc.title.startsWith("Huckle")))
.fetch();
```

This is transformed into the following Lucene query:

```
+year:[1800 TO 2000] +title:huckle*
```

### Custom Serializer

The default `LuceneSerializer` does not lowercase terms and splits on
whitespace. To customize this behavior, pass a serializer to the query:

```java
LuceneSerializer serializer = new LuceneSerializer(true, true);
LuceneQuery query = new LuceneQuery(serializer, searcher);
```

The constructor parameters are:

| Parameter | Description |
|:----------|:------------|
| `lowerCase` | Convert search terms to lowercase |
| `splitTerms` | Split terms by whitespace into multi-term queries |

## Typed Queries

Use `TypedQuery` to transform Lucene documents into custom types:

```java
TypedQuery<Person> query = new TypedQuery<>(searcher, doc -> {
Person person = new Person();
person.setName(doc.get("name"));
person.setAge(Integer.parseInt(doc.get("age")));
return person;
});
List<Person> results = query.where(doc.title.eq("Engineer")).fetch();
```

## General Usage

Use the cascading methods of the `LuceneQuery` class:

**where:** Add query filters, either in varargs form separated via commas or
cascaded via the and-operator. Supported operations include equality, inequality,
range queries, string matching (`like`, `startsWith`, `endsWith`, `contains`),
and collection operations (`in`, `notIn`).

**orderBy:** Add ordering of the result as a varargs array of order
expressions. Use `asc()` and `desc()` on numeric, string, and other comparable
expressions to access the `OrderSpecifier` instances.

**limit, offset, restrict:** Set the paging of the result. `limit` for max
results, `offset` for skipping rows, and `restrict` for defining both in one
call.

**load:** Select specific fields to load from the index instead of loading
the entire document.

## Ordering

```java
query
.where(doc.title.like("*"))
.orderBy(doc.title.asc(), doc.year.desc())
.fetch();
```

This is equivalent to the Lucene query `title:*` with results sorted ascending
by title and descending by year.

Alternatively, use a `Sort` instance directly:

```java
Sort sort = ...;
query
.where(doc.title.like("*"))
.sort(sort)
.fetch();
```

## Limit

```java
query
.where(doc.title.like("*"))
.limit(10)
.fetch();
```

## Offset

```java
query
.where(doc.title.like("*"))
.offset(3)
.fetch();
```

## Field Selection

Load only specific fields from the index:

```java
query
.where(doc.title.ne(""))
.load(doc.title)
.fetch();
```

## Fuzzy Searches

Fuzzy searches can be expressed via `fuzzyLike` methods in the
`LuceneExpressions` class:

```java
query
.where(LuceneExpressions.fuzzyLike(doc.title, "Hello"))
.fetch();
```

You can also control the maximum edit distance and prefix length:

```java
query
.where(LuceneExpressions.fuzzyLike(doc.title, "Hello", 2, 0))
.fetch();
```

## Applying Lucene Filters

Apply a native Lucene `Query` as a filter:

```java
query
.where(doc.title.like("*"))
.filter(IntPoint.newExactQuery("year", 1990))
.fetch();
```
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,14 @@
<title>Lucene 5</title>
<packages>com.querydsl.lucene5*</packages>
</group>
<group>
<title>Lucene 9</title>
<packages>com.querydsl.lucene9*</packages>
</group>
<group>
<title>Lucene 10</title>
<packages>com.querydsl.lucene10*</packages>
</group>
<group>
<title>Hibernate Search</title>
<packages>com.querydsl.hibernate.search*</packages>
Expand Down
4 changes: 4 additions & 0 deletions querydsl-libraries/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<!-- Languages -->
<module>querydsl-scala</module>
<module>querydsl-kotlin</module>

<!-- Lucene -->
<module>querydsl-lucene9</module>
<module>querydsl-lucene10</module>
</modules>

<dependencyManagement>
Expand Down
57 changes: 57 additions & 0 deletions querydsl-libraries/querydsl-lucene10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Querydsl Lucene 10

The Lucene module provides integration with the Lucene 10 indexing library.

**Maven integration**

Add the following dependencies to your Maven project :
```XML
<dependency>
<groupId>io.github.openfeign.querydsl</groupId>
<artifactId>querydsl-lucene10</artifactId>
<version>${querydsl.version}</version>
</dependency>
```

**Creating the query types**

With fields year and title a manually created query type could look something like this:

```JAVA
public class QDocument extends EntityPathBase<Document>{
private static final long serialVersionUID = -4872833626508344081L;

public QDocument(String var) {
super(Document.class, PathMetadataFactory.forVariable(var));
}

public final StringPath year = createString("year");

public final StringPath title = createString("title");
}
```

QDocument represents a Lucene document with the fields year and title.

Code generation is not available for Lucene, since no schema data is available.

**Querying**

Querying with Querydsl Lucene is as simple as this:

```JAVA
QDocument doc = new QDocument("doc");

IndexSearcher searcher = new IndexSearcher(index);
LuceneQuery query = new LuceneQuery(true, searcher);
List<Document> documents = query
.where(doc.year.between("1800", "2000").and(doc.title.startsWith("Huckle"))
.fetch();
```

which is transformed into the following Lucene query :
```
+year:[1800 TO 2000] +title:huckle*
```

For more information on the Querydsl Lucene module visit the reference documentation http://www.querydsl.com/static/querydsl/latest/reference/html/ch02s05.html
Loading
Loading