[[getting-started]]
== Getting started

Welcome to Hibernate Search. The following chapter will guide you through the initial steps required
to integrate Hibernate Search into an existing Hibernate ORM enabled application. In case you are a
Hibernate new timer we recommend you start link:http://hibernate.org/quick-start.html[here].

=== System Requirements

.System requirements

|===============
|Java Runtime|Requires Java version _8_ or greater. You
            can download a Java Runtime for Windows/Linux/Solaris link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[here].
|Hibernate Search| `hibernate-search-{hibernateSearchVersion}.jar` and all
            runtime dependencies. You can get the jar artifacts either from
            the `dist/lib` directory of the link:http://sourceforge.net/projects/hibernate/files/hibernate-search/[Hibernate Search distribution] or you can download them from the
            Maven Central repository.
|Hibernate ORM|You will need
            `hibernate-core-{hibernateVersion}.jar` and its
            dependencies (either from the link:http://sourceforge.net/projects/hibernate/files/hibernate-orm/[distribution bundle] or the maven repository).
|JPA 2.1|Hibernate Search can be used without JPA but the following instructions will use JPA annotations for basic
            entity configuration (`@Entity`, `@Id`, `@OneToMany`,...).
|===============

=== Migration notes

If you are upgrading an existing application from an earlier version of Hibernate Search to the latest release,
make sure to check the out the http://hibernate.org/search/documentation/migrate/[migration guide].

=== Required libraries

The Hibernate Search library is split in several modules to allow you to pick the minimal set of
dependencies you need.
It requires Apache Lucene, Hibernate ORM and some standard APIs such as the Java Persistence API
and the Java Transactions API. Other dependencies are optional, providing additional integration
points.
To get the correct jar files on your classpath we highly recommend to use a dependency manager such
as http://maven.apache.org/[Maven], or similar tools such as http://www.gradle.org/[Gradle] or
http://ant.apache.org/ivy/[Ivy].
These alternatives are also able to consume the artifacts from the <<search-download-via-maven>> section.


[[search-download-via-maven]]
==== Using Maven

The Hibernate Search artifacts can be found in Maven's http://central.sonatype.org/[Central Repository]
but are released first in the http://repository.jboss.org/nexus/content/groups/public-jboss/[JBoss Maven Repository].
See also the https://community.jboss.org/wiki/MavenGettingStarted-Users[Maven Getting Started wiki page] to use
the JBoss repository.

All you have to add to your pom.xml is:

.Maven artifact identifier for Hibernate Search
====
[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-search-orm</artifactId>
   <version>{hibernateSearchVersion}</version>
</dependency>
----
====

.Optional Maven dependencies for Hibernate Search
====
[source, XML]
[subs="verbatim,attributes"]
<!-- Infinispan integration: -->
<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>infinispan-directory-provider</artifactId>
   <version>{infinispanVersion}</version>
</dependency>
====

Only the _hibernate-search-orm_ dependency is mandatory. _infinispan-directory-provider_ is only required
if you want to use Infinispan to store the Lucene indexes.

==== Manual library management

You can download zip bundles from Sourceforge containing all needed
http://sourceforge.net/projects/hibernate/files/hibernate-search/{hibernateSearchVersion}/[Hibernate Search]
dependencies. This includes - among others - the latest compatible version of Hibernate ORM. However,
only the essential parts you need to start experimenting with are included. You will probably need
to combine this with downloads from the other projects, for example the
http://sourceforge.net/projects/hibernate/files/hibernate-orm/{hibernateVersion}/[Hibernate ORM distribution on Sourceforge]
also provides the modules to enable caching or use a connection pool.

=== Deploying on WildFly

If you are creating an application to be deployed on WildFly you're lucky:
Hibernate Search is included in the application server.
This means that you don't need to package it along with your application, unless you want to use a different version
than the one included.
Since WildFly version 10 the embedded version of Hibernate Search is automatically activated when your application uses it. See <<search-configuration-deploy-on-wildfly>> for details.

Since this version of Hibernate Search requires Hibernate ORM version `5.2.3+` - which is more recent than the Hibernate ORM
version included in WildFly - you will also need to follow the instructions in the http://docs.jboss.org/hibernate/orm/5.2/topical/html_single/wildfly/Wildfly.html[Hibernate ORM WildFly upgrade guide].

=== Configuration

Once you have added all required dependencies to your application you have to add a couple of
properties to your Hibernate configuration file.
If you are using Hibernate directly this can be done in `hibernate.properties` or `hibernate.cfg.xml`.
If you are using Hibernate via JPA you can also add the properties to `persistence.xml`.
The good news is that for standard use most properties offer a sensible default.
An example `persistence.xml` configuration could look like this:

.Basic configuration options to be added to `hibernate.properties`, `hibernate.cfg.xml` or `persistence.xml`
====
[source, XML]
----
...
<property name="hibernate.search.default.directory_provider"
          value="filesystem"/>

<property name="hibernate.search.default.indexBase"
          value="/var/lucene/indexes"/>
...
----
====

First you have to tell Hibernate Search which `DirectoryProvider` to use. This can be achieved by
setting the `hibernate.search.default.directory_provider` property. Apache Lucene has the notion
of a `Directory` to store the index files. Hibernate Search handles the initialization and
configuration of a Lucene `Directory` instance via a `DirectoryProvider`. In this tutorial we will
use a a directory provider which stores the index on the file system. This will give us the ability to
inspect the Lucene indexes created by Hibernate Search (eg via
link:https://github.com/DmitryKey/luke/[Luke]). Once you have a working configuration you can start
experimenting with other directory providers (see <<search-configuration-directory>>).
You also have to specify the default base directory for all indexes via
`hibernate.search.default.indexBase`. This defines the path where indexes are stored.

Let's assume that your application contains the Hibernate managed classes `example.Book` and
`example.Author` and you want to add free text search capabilities to your application in order to
search the books contained in your database.

.Example entities Book and Author before adding Hibernate Search specific annotations
====
[source, JAVA]
----
package example;
...
@Entity
public class Book {

  @Id
  @GeneratedValue
  private Integer id;

  private String title;

  private String subtitle;

  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();

  private Date publicationDate;

  public Book() {}

  // standard getters/setters follow
  ...
}
----


[source, JAVA]
----
package example;
...
@Entity
public class Author {

  @Id
  @GeneratedValue
  private Integer id;

  private String name;

  public Author() {}

  // standard getters/setters follow
  ...
}
----
====

To achieve this you have to add a few annotations to the `Book` and `Author` class. The first annotation
`@Indexed` marks `Book` as indexable. By design Hibernate Search needs to store an _untokenized_ id in
the index to ensure index uniqueness for a given entity (for now don't worry if you don't know what
_untokenized_ means, it will soon be clear).

Next you have to mark the fields you want to make searchable. Let's start with `title` and
`subtitle` and annotate both with `@Field`. The parameter `index=Index.YES` will ensure that the
text will be indexed, while `analyze=Analyze.YES` ensures that the text will be analyzed using the
default Lucene analyzer. Usually, analyzing or tokenizing means chunking a sentence into individual
words and potentially excluding common words like "a" or "the". We will talk more about analyzers a
little later on.
The third parameter we specify is `store=Store.NO`, which ensures that the actual data
will not be stored in the index.
Whether data is stored in the index or not has nothing to do with the ability to search for it.
It is not necessary to store fields in the index to allow Lucene to search for them: the benefit of
storing them is the ability to retrieve them via projections (see <<projections>>).

Without projections, Hibernate Search will per default execute a Lucene query in order to find the
database identifiers of the entities matching the query criteria and use these identifiers to
retrieve managed objects from the database. The decision for or against projection has to be made on
a case by case basis.

Note that `index=Index.YES`, `analyze=Analyze.YES` and `store=Store.NO` are the default values for
these parameters and could be omitted.

After this short look under the hood let's go back to annotating the `Book` class. Another annotation
we have not yet discussed is `@DateBridge`. This annotation is one of the built-in field bridges in
Hibernate Search. The Lucene index is mostly string based, with special support for encoding numbers.
Hibernate Search must convert the data types of the indexed fields to their respective Lucene
encoding and vice versa. A range of predefined bridges is provided for this purpose, including the
`DateBridge` which will convert a `java.util.Date` into a numeric value (a `long`) with the
specified resolution. For more details see <<section-built-in-bridges>>.

This leaves us with `@IndexedEmbedded`. This annotation is used to index associated entities
(`@ManyToMany`, `@*ToOne`, `@Embedded` and `@ElementCollection`) as part of the owning entity.
This is needed since a Lucene index document is a flat data structure which does not know anything
about object relations.
To ensure that the author names will be searchable you have to make sure that the names are indexed
as part of the book itself. On top of `@IndexedEmbedded` you will also have to mark the fields of
the associated entity you want to have included in the index with `@Field`.
For more details see <<search-mapping-associated>>.

These settings should be sufficient for now. For more details on entity mapping refer to
<<search-mapping-entity>>.

.Example entities after adding Hibernate Search annotations
====
[source, JAVA]
----
package example;
...
@Entity
@Indexed
public class Book {

  @Id
  @GeneratedValue
  private Integer id;

  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  private String title;

  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  private String subtitle;

  @Field(index = Index.YES, analyze=Analyze.NO, store = Store.YES)
  @DateBridge(resolution = Resolution.DAY)
  private Date publicationDate;

  @IndexedEmbedded
  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();
  public Book() {
  }

  // standard getters/setters follow here
  ...
}
----

[source, JAVA]
----
@Entity
public class Author {

  @Id
  @GeneratedValue
  private Integer id;

  @Field
  private String name;

  public Author() {
  }

  // standard getters/setters follow here
  ...
}
====


=== Indexing

Hibernate Search will transparently index every entity persisted, updated or removed through
Hibernate ORM. However, you have to create an initial Lucene index for the data already present in
your database. Once you have added the above properties and annotations it is time to trigger an
initial batch index of your books. You can achieve this by using one of the following code snippets
(see also <<search-batchindex>>):

.Using Hibernate Session to index data
====
[source, JAVA]
----
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
----
====

.Using JPA to index data
====
[source, JAVA]
----
EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
fullTextEntityManager.createIndexer().startAndWait();
----
====

After executing the above code, you should be able to see a Lucene index under `/var/lucene/indexes/example.Book`
(or based on a different path depending how you configured the property `hibernate.search.default.directory_provider`).

Go ahead an inspect this index with link:https://github.com/DmitryKey/luke/[Luke]:
it will help you to understand how Hibernate Search works.

=== Searching

Now it is time to execute a first search. The general approach is to create a Lucene query, either
via the Lucene API (<<search-query-lucene-api>>) or via the Hibernate Search query DSL
(<<search-query-querydsl>>), and then wrap this query into a `org.hibernate.Query` in order to get all the
functionality one is used to from the Hibernate API. The following code will prepare a query against
the indexed fields, execute it and return a list of `Book` instances.

.Using Hibernate Session to create and execute a search
====
[source, JAVA]
----
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();

// create native Lucene query using the query DSL
// alternatively you can write the Lucene query using the Lucene query parser
// or the Lucene programmatic API. The Hibernate Search DSL is recommended though
QueryBuilder qb = fullTextSession.getSearchFactory()
  .buildQueryBuilder().forEntity(Book.class).get();
org.apache.lucene.search.Query query = qb
  .keyword()
  .onFields("title", "subtitle", "authors.name")
  .matching("Java rocks!")
  .createQuery();

// wrap Lucene query in a org.hibernate.Query
org.hibernate.Query hibQuery =
    fullTextSession.createFullTextQuery(query, Book.class);

// execute search
List result = hibQuery.list();

tx.commit();
session.close();
----
====

.Using JPA to create and execute a search
====
[source, JAVA]
----
EntityManager em = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager =
    org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
em.getTransaction().begin();

// create native Lucene query using the query DSL
// alternatively you can write the Lucene query using the Lucene query parser
// or the Lucene programmatic API. The Hibernate Search DSL is recommended though
QueryBuilder qb = fullTextEntityManager.getSearchFactory()
    .buildQueryBuilder().forEntity(Book.class).get();
org.apache.lucene.search.Query query = qb
  .keyword()
  .onFields("title", "subtitle", "authors.name")
  .matching("Java rocks!")
  .createQuery();

// wrap Lucene query in a javax.persistence.Query
javax.persistence.Query persistenceQuery =
    fullTextEntityManager.createFullTextQuery(query, Book.class);

// execute search
List result = persistenceQuery.getResultList();

em.getTransaction().commit();
em.close();
----
====


=== Analyzer

Let's make things a little more interesting now. Assume that one of your indexed book entities has
the title "Refactoring: Improving the Design of Existing Code" and you want to get hits for all of
the following queries: "refactor", "refactors", "refactored" and "refactoring". In Lucene this can
be achieved by choosing an analyzer class which applies word stemming during the indexing *as well
as* the search process. Hibernate Search offers several ways to configure the analyzer to be used
(see <<analyzer>>):

* Setting the `hibernate.search.analyzer` property in the configuration file.
The specified class will then be the default analyzer.
* Setting the `@Analyzer` annotation at the entity level.
* Setting the `@Analyzer` annotation at the field level.

When using the `@Analyzer` annotation one can either specify the fully qualified classname of the
analyzer to use or one can refer to an analyzer definition defined by the `@AnalyzerDef` annotation.
In the latter case the analyzer framework with its factories approach is utilized.

To find out more about the factory classes available
you can either browse the Lucene JavaDoc or read the corresponding section on the
link:http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters[Solr Wiki].

You can use `@AnalyzerDef` on any:

* `@Indexed` entity regardless of where the analyzer is applied to;
* parent class of an `@Indexed` entity;
* package-info.java of a package containing an `@Indexed` entity.

This implies that analyzer definitions are global and their names must be unique.
The `@AnalyzerDef` is a repeatable annotation, so you can declare multiple analyzer
definitions on each of these types.

[NOTE]
====
Why the reference to the Apache Solr wiki?

The analyzer factory framework was originally created in the Apache Solr project.
Most of these implementations have been moved to Apache Lucene, but the
documentation for these additional analyzers can still be found in the Solr Wiki. You might find
other documentation referring to the "Solr Analyzer Framework"; just remember you don't need to
depend on Apache Solr anymore: the required classes are part of the core Lucene distribution.
====

In the example below a `StandardTokenizerFactory` is used followed by two filter factories,
`LowerCaseFilterFactory` and `SnowballPorterFilterFactory`. The standard tokenizer splits words at
punctuation characters and hyphens.
It is a good general purpose tokenizer.
For indexing email addresses or internet hostnames it is not the best fit as it would split them up.
You may either make use of Lucene's `ClassicTokenizerFactory` in such cases or implement a custom tokenizer and factory.
The lowercase filter converts to lowercase the letters in each token
whereas the snowball filter finally applies language specific stemming.

Generally, when using the Analyzer Framework you have to start with a tokenizer followed by an
arbitrary number of filters.


.Using `@AnalyzerDef` and the Analyzer Framework to define and use an analyzer
====
[source, JAVA]
----
@Entity
@Indexed
@AnalyzerDef(name = "customanalyzer",
  tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
  filters = {
    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
    @TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = {
      @Parameter(name = "language", value = "English")
    })
  })
public class Book {

  @Id
  @GeneratedValue
  @DocumentId
  private Integer id;

  @Field
  @Analyzer(definition = "customanalyzer")
  private String title;

  @Field
  @Analyzer(definition = "customanalyzer")
  private String subtitle;

  @IndexedEmbedded
  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();

  @Field(index = Index.YES, analyze = Analyze.NO, store = Store.YES)
  @DateBridge(resolution = Resolution.DAY)
  private Date publicationDate;

  public Book() {
  }

  // standard getters/setters follow here
  ...
}
====

Using `@AnalyzerDef` only defines an Analyzer, you still have to apply it to entities and or
properties using `@Analyzer`. Like in the above example the `customanalyzer` is defined but not
applied on the entity: it's applied on the `title` and `subtitle` properties only. An analyzer
definition is global, so you can define it on any entity and reuse the definition on other entities.

=== What's next

The above paragraphs helped you getting an overview of Hibernate Search. The next step after this
tutorial is to get more familiar with the overall architecture of Hibernate Search
(<<search-architecture>>) and explore the basic features in more detail. Two topics which were only briefly
touched in this tutorial were analyzer configuration (<<analyzer>>) and field bridges
(<<search-mapping-bridge>>). Both are important features required for more fine-grained indexing. More
advanced topics cover clustering (<<jms-backend>>, <<infinispan-directories>>) and large index
handling (<<advanced-features-sharding>>).
