Skip to content

Commit

Permalink
Merge pull request #11 from gsmet/index-topics-extensions
Browse files Browse the repository at this point in the history
Index topics and extensions and various other tweaks
  • Loading branch information
yrodiere authored Oct 11, 2023
2 parents 4890c7a + b22fcae commit 79b1eae
Show file tree
Hide file tree
Showing 17 changed files with 324 additions and 208 deletions.
29 changes: 16 additions & 13 deletions src/main/java/io/quarkus/search/app/SearchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,23 @@ public class SearchService {
public SearchResult<SearchHit> search(@RestQuery String q) {
var result = session.search(Guide.class)
.select(SearchHit.class)
.where((f, root) -> {
root.add(f.matchAll()); // Default
if (q != null && !q.isBlank()) {
root.add(f.simpleQueryString()
.field("keywords").boost(10.0f)
.field("title").boost(7.0f)
.field("summary").boost(5.0f)
.field("fullContent")
.field("keywords_autocomplete").boost(1.0f)
.field("title_autocomplete").boost(0.7f)
.field("summary_autocomplete").boost(0.5f)
.field("fullContent_autocomplete").boost(0.1f)
.matching(q));
.where(f -> {
if (q == null || q.isBlank()) {
return f.matchAll();
}

return f.bool().must(f.simpleQueryString()
.field("title").boost(10.0f)
.field("topics").boost(10.0f)
.field("keywords").boost(10.0f)
.field("summary").boost(5.0f)
.field("fullContent")
.field("keywords_autocomplete").boost(1.0f)
.field("title_autocomplete").boost(1.0f)
.field("summary_autocomplete").boost(0.5f)
.field("fullContent_autocomplete").boost(0.1f)
.matching(q))
.should(f.not(f.match().field("topics").matching("compatibility")).boost(50.0f));
})
.sort(f -> f.score().then().field("title_sort"))
.fetch(20);
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/io/quarkus/search/app/entity/Guide.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

import java.util.Set;

import org.hibernate.Length;
import org.hibernate.search.engine.backend.types.Aggregable;
import org.hibernate.search.engine.backend.types.Projectable;
import org.hibernate.search.engine.backend.types.Searchable;
import org.hibernate.search.engine.backend.types.Sortable;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
Expand Down Expand Up @@ -42,6 +46,13 @@ public class Guide {
// Using PathWrapper because of https://hibernate.atlassian.net/browse/HSEARCH-4988
public PathWrapper fullContentPath;

@FullTextField(name = "topics")
@KeywordField(name = "topics_faceting", searchable = Searchable.YES, projectable = Projectable.YES, aggregable = Aggregable.YES)
public Set<String> topics;

@KeywordField(name = "extensions_faceting", searchable = Searchable.YES, projectable = Projectable.YES, aggregable = Aggregable.YES)
public Set<String> extensions;

@Override
public String toString() {
return "Guide{" +
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/io/quarkus/search/app/fetching/QuarkusIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.io.FilenameUtils;
Expand Down Expand Up @@ -40,8 +44,19 @@ private Guide parseGuide(Path path) {
guide.fullContentPath = new PathWrapper(path);
Asciidoc.parse(path, title -> guide.title = title,
Map.of("summary", summary -> guide.summary = summary,
"keywords", keywords -> guide.keywords = keywords));
"keywords", keywords -> guide.keywords = keywords,
"topics", topics -> guide.topics = toSet(topics),
"extensions", extensions -> guide.extensions = toSet(extensions)));
return guide;
}

private static Set<String> toSet(String value) {
if (value == null || value.isBlank()) {
return Set.of();
}

return Arrays.stream(value.split(","))
.map(String::trim)
.collect(Collectors.toCollection(HashSet::new));
}
}
3 changes: 2 additions & 1 deletion src/test/data/quarkusio/_guides/duplicated-context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc
include::_attributes.adoc[]
:diataxis-type: concept
:categories: core, architecture
:topics: internals,extensions

When using a traditional, blocking, and synchronous framework, processing of each request is performed in a dedicated thread.
So, the same thread is used for the entire processing.
Expand Down Expand Up @@ -247,4 +248,4 @@ The OpenTelemetry extension stores the traces in the duplicated context, ensurin

- xref:quarkus-reactive-architecture.adoc[Quarkus Reactive Architecture]
- https://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor[Vert.x Reactor and Multi-Reactor documentation]
- xref:logging.adoc[Quarkus logging]
- xref:logging.adoc[Quarkus logging]
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ include::_attributes.adoc[]
:categories: data, alt-languages
:summary: This explains the specifics of using Hibernate ORM with Panache in a Kotlin project.
:config-file: application.properties
:topics: data,hibernate-orm,panache,kotlin,sql,jdbc
:extensions: io.quarkus:quarkus-hibernate-orm-panache-kotlin,io.quarkus:quarkus-hibernate-orm-panache,io.quarkus:quarkus-hibernate-orm

Hibernate ORM is the de facto standard Jakarta Persistence (formerly known as JPA) implementation and is well-known in the Java ecosystem. Hibernate ORM with Panache offers a
new layer atop this familiar framework. This guide will not dive in to the specifics of either as those are already
covered in the xref:hibernate-orm-panache.adoc[Hibernate ORM with Panache guide]. In this guide, we'll cover the Kotlin specific changes
needed to use Hibernate ORM with Panache in your Kotlin-based Quarkus applications.

NOTE: When using the kotlin version of Hibernate ORM with Panache, note that the `PanacheEntity`, `PanacheQuery` and `PanacheRepository` are in a different package: `io.quarkus.hibernate.orm.panache.kotlin`.
NOTE: When using the Kotlin version of Hibernate ORM with Panache, note that the `PanacheEntity`, `PanacheQuery` and `PanacheRepository` are in a different package: `io.quarkus.hibernate.orm.panache.kotlin`.

== First: an example

Expand Down
6 changes: 4 additions & 2 deletions src/test/data/quarkusio/_guides/hibernate-orm-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ include::_attributes.adoc[]
:categories: data
:summary: Hibernate ORM is the de facto Jakarta Persistence implementation and offers you the full breadth of an Object Relational Mapper. It makes complex mappings possible, but it does not make simple and common mappings trivial. Panache focuses on making your entities trivial and fun to write.
:config-file: application.properties
:topics: data,hibernate-orm,panache,sql,jdbc
:extensions: io.quarkus:quarkus-hibernate-orm-panache,io.quarkus:quarkus-hibernate-orm

Hibernate ORM is the de facto Jakarta Persistence (formerly known as JPA) implementation and offers you the full breadth of an Object Relational Mapper.
It makes complex mappings possible, but it does not make simple and common mappings trivial.
Expand Down Expand Up @@ -944,7 +946,7 @@ matching the values returned by the select clause:
----
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
@RegisterForReflection
public class RaceWeight {
public final String race;
public final Double weight;
Expand Down Expand Up @@ -1198,7 +1200,7 @@ public class PanacheFunctionalityTest {
// We can even mock your custom methods
Mockito.when(Person.findOrdered()).thenReturn(Collections.emptyList());
Assertions.assertTrue(Person.findOrdered().isEmpty());
// Mocking a void method
Person.voidMethod();
Expand Down
36 changes: 19 additions & 17 deletions src/test/data/quarkusio/_guides/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ include::_attributes.adoc[]
:categories: data
:summary: Hibernate ORM is the de facto Jakarta Persistence implementation and offers you the full breath of an Object Relational Mapper. It works beautifully in Quarkus.
:config-file: application.properties
:topics: data,hibernate-orm,sql,jdbc
:extensions: io.quarkus:quarkus-hibernate-orm

Hibernate ORM is the de facto standard Jakarta Persistence (formerly known as JPA) implementation and offers you the full breadth of an Object Relational Mapper.
It works beautifully in Quarkus.
Expand Down Expand Up @@ -97,12 +99,12 @@ They will often map to Hibernate ORM configuration properties but could have dif

Also, Quarkus will set many Hibernate ORM configuration settings automatically, and will often use more modern defaults.

For a list of the items that you can set in `{config-file}`, see xref:hibernate-configuration-properties[Hibernate ORM configuration properties].
For a list of the items that you can set in `{config-file}`, see <<hibernate-configuration-properties,Hibernate ORM configuration properties>>.

An `EntityManagerFactory` will be created based on the Quarkus `datasource` configuration as long as the Hibernate ORM extension is listed among your project dependencies.

The dialect will be selected and configured automatically based on your datasource;
you may want to xref:hibernate-dialect[configure it to more precisely match your database].
you may want to <<hibernate-dialect,configure it to more precisely match your database>>.

You can then happily inject your `EntityManager`:

Expand Down Expand Up @@ -234,7 +236,7 @@ In that case, keep in mind that the JDBC driver or Hibernate ORM dialect
may not work properly in GraalVM native executables.
====

As with xref:hibernate-dialect-supported-databases[supported databases],
As with <<hibernate-dialect-supported-databases,supported databases>>,
you can configure the DB version explicitly to get the most out of Hibernate ORM:

[source,properties]
Expand Down Expand Up @@ -268,7 +270,7 @@ include::{generated-dir}/config/quarkus-hibernate-orm.adoc[opts=optional, levelo

[NOTE]
====
Do not mix xref:persistence-xml[`persistence.xml`] and `quarkus.hibernate-orm.*` properties in `{config-file}`.
Do not mix <<persistence-xml,`persistence.xml`>> and `quarkus.hibernate-orm.*` properties in `{config-file}`.
Quarkus will raise an exception.
Make up your mind on which approach you want to use.
Expand Down Expand Up @@ -537,7 +539,7 @@ the https://jakarta.ee/specifications/persistence/3.0/jakarta-persistence-spec-3
or the http://hibernate.org/dtd/hibernate-mapping-3.0.dtd[`hbm.xml` format (specific to Hibernate ORM, deprecated)]:

* in `application.properties` through the (build-time) link:#quarkus-hibernate-orm_quarkus.hibernate-orm.mapping-files[`quarkus.hibernate-orm.mapping-files`] property.
* in xref:persistence-xml[`persistence.xml`] through the `<mapping-file>` element.
* in <<persistence-xml,`persistence.xml`>> through the `<mapping-file>` element.

XML mapping files are parsed at build time.

Expand Down Expand Up @@ -856,13 +858,13 @@ configure your datasource as in the above examples and it will set up Hibernate
More details about this connection pool can be found in xref:datasource.adoc[Quarkus - Datasources].

Second Level Cache::
As explained earlier in the xref:caching[Caching section], you don't need to pick an implementation.
As explained earlier in the <<caching,Caching section>>, you don't need to pick an implementation.
A suitable implementation based on technologies from link:https://infinispan.org/[Infinispan] and link:https://github.com/ben-manes/caffeine[Caffeine] is included as a transitive dependency of the Hibernate ORM extension, and automatically integrated during the build.

=== Limitations

XML mapping with duplicate files in the classpath::
xref:xml-mapping[XML mapping] files are expected to have a unique path.
<<xml-mapping,XML mapping>> files are expected to have a unique path.
+
In practice, it's only possible to have duplicate XML mapping files in the classpath in very specific scenarios.
For example, if two JARs include a `META-INF/orm.xml` file (with the exact same path but in different JARs),
Expand Down Expand Up @@ -944,7 +946,7 @@ public class FruitResource {
return entityManager.createNamedQuery("Fruits.findAll", Fruit.class)
.getResultList().toArray(new Fruit[0]);
}
}
----

Expand All @@ -968,7 +970,7 @@ public class CustomTenantResolver implements TenantResolver {
public String getDefaultTenantId() {
return "base";
}
@Override
public String resolveTenantId() {
String path = context.request().path();
Expand All @@ -981,13 +983,13 @@ public class CustomTenantResolver implements TenantResolver {
return parts[1];
}
}
----
<1> Annotate the TenantResolver implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For xref:multiple-persistence-units[named persistence units], use `@PersistenceUnitExtension("nameOfYourPU")`.
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`.
<2> The bean is made `@RequestScoped` as the tenant resolution depends on the incoming request.

From the implementation above, tenants are resolved from the request path so that in case no tenant could be inferred, the default tenant identifier is returned.
Expand Down Expand Up @@ -1026,7 +1028,7 @@ The following setup will use the xref:flyway.adoc[Flyway] extension to achieve t
==== SCHEMA approach

The same data source will be used for all tenants and a schema has to be created for every tenant inside that data source.
CAUTION: Some databases like MariaDB/MySQL do not support database schemas. In these cases you have to use the DATABASE approach below.
CAUTION: Some databases like MariaDB/MySQL do not support database schemas. In these cases you have to use the DATABASE approach below.

[source,properties]
----
Expand All @@ -1035,7 +1037,7 @@ quarkus.hibernate-orm.database.generation=none
# Enable SCHEMA approach and use default datasource
quarkus.hibernate-orm.multitenant=SCHEMA
# You could use a non-default datasource by using the following setting
# You could use a non-default datasource by using the following setting
# quarkus.hibernate-orm.multitenant-schema-datasource=other
# The default data source used for all tenant schemas
Expand Down Expand Up @@ -1081,7 +1083,7 @@ INSERT INTO mycompany.known_fruits(id, name) VALUES (3, 'Blackberries');

==== DATABASE approach

For every tenant you need to create a named data source with the same identifier that is returned by the `TenantResolver`.
For every tenant you need to create a named data source with the same identifier that is returned by the `TenantResolver`.

[source,properties]
----
Expand Down Expand Up @@ -1171,7 +1173,7 @@ quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_test
If you need a more dynamic configuration for the different tenants you want to support and don't want to end up with multiple entries in your configuration file,
you can use the `io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver` interface to implement your own logic for retrieving a connection.
Creating an application-scoped bean that implements this interface
and annotating it with `@PersistenceUnitExtension` (or `@PersistenceUnitExtension("nameOfYourPU")` for a xref:multiple-persistence-units[named persistence unit])
and annotating it with `@PersistenceUnitExtension` (or `@PersistenceUnitExtension("nameOfYourPU")` for a <<multiple-persistence-units,named persistence unit>>)
will replace the current Quarkus default implementation `io.quarkus.hibernate.orm.runtime.tenant.DataSourceTenantConnectionResolver`.
Your custom connection resolver would allow for example to read tenant information from a database and create a connection per tenant at runtime based on it.

Expand All @@ -1196,7 +1198,7 @@ public static class MyInterceptor extends EmptyInterceptor { // <2>
<1> Annotate the interceptor implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For xref:multiple-persistence-units[named persistence units], use `@PersistenceUnitExtension("nameOfYourPU")`
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<2> Either extend `org.hibernate.EmptyInterceptor` or implement `org.hibernate.Interceptor` directly.
<3> Implement methods as necessary.

Expand Down Expand Up @@ -1238,5 +1240,5 @@ public class MyStatementInspector implements StatementInspector { // <2>
<1> Annotate the statement inspector implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For xref:multiple-persistence-units[named persistence units], use `@PersistenceUnitExtension("nameOfYourPU")`
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<2> Implement `org.hibernate.engine.jdbc.spi.StatementInspector`.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ include::_attributes.adoc[]
:categories: data
:summary: Simplified reactive ORM layer based on Hibernate Reactive.
:config-file: application.properties
:topics: data,hibernate-reactive,panache,sql
:extensions: io.quarkus:quarkus-hibernate-reactive-panache,io.quarkus:quarkus-hibernate-reactive

link:https://hibernate.org/reactive/[Hibernate Reactive] is the only reactive Jakarta Persistence (formerly known as JPA) implementation and offers you the full
breadth of an Object Relational Mapper allowing you to access your database over reactive drivers.
Expand Down
10 changes: 3 additions & 7 deletions src/test/data/quarkusio/_guides/hibernate-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ include::_attributes.adoc[]
:config-file: application.properties
:reactive-doc-url-prefix: https://hibernate.org/reactive/documentation/1.1/reference/html_single/#getting-started
:extension-status: preview
:topics: data,hibernate-reactive,panache,sql
:extensions: io.quarkus:quarkus-hibernate-reactive-panache,io.quarkus:quarkus-hibernate-reactive

link:https://hibernate.org/reactive/[Hibernate Reactive] is a reactive API for Hibernate ORM, supporting non-blocking database drivers
and a reactive style of interaction with the database.
Expand Down Expand Up @@ -114,7 +116,7 @@ Also, Quarkus will set many Hibernate Reactive configuration settings automatica

WARNING: Configuring Hibernate Reactive using the standard `persistence.xml` configuration file is not supported.

See section xref:hr-configuration-properties[Hibernate Reactive configuration properties] for the list of properties you can set in `{config-file}`.
See section <<hr-configuration-properties,Hibernate Reactive configuration properties>> for the list of properties you can set in `{config-file}`.

A `Mutiny.SessionFactory` will be created based on the Quarkus `datasource` configuration as long as the Hibernate Reactive extension is listed among your project dependencies.

Expand Down Expand Up @@ -301,12 +303,6 @@ it's not possible to configure multiple persistence units,
or even a single named persistence unit.
* This extension cannot be used at the same time as Hibernate ORM.
See https://github.com/quarkusio/quarkus/issues/13425.
* This extension cannot be used at the same time as JDBC/Agroal.
See https://github.com/quarkusio/quarkus/issues/33380.
+
This also means this extension cannot be used at the same time as extensions that rely on JDBC,
such as the Flyway extension.
See https://github.com/quarkusio/quarkus/issues/10716.
* Integration with the Envers extension is not supported.
* Transaction demarcation cannot be done using `jakarta.transaction.Transactional` or `QuarkusTransaction`;
if you use xref:hibernate-reactive-panache.adoc[Hibernate Reactive with Panache],
Expand Down
Loading

0 comments on commit 79b1eae

Please sign in to comment.