You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dw...@apache.org on 2021/03/10 09:59:54 UTC

[lucene] 41/50: SOLR-11032: Update SolrJ tutorial with new example test for real tested code samples

This is an automated email from the ASF dual-hosted git repository.

dweiss pushed a commit to branch branch_7_1
in repository https://gitbox.apache.org/repos/asf/lucene.git

commit 45ebbc7a94a9a7b43ae1d2e7c1b37380cac301d8
Author: Cassandra Targett <ct...@apache.org>
AuthorDate: Thu Oct 26 15:25:05 2017 -0500

    SOLR-11032: Update SolrJ tutorial with new example test for real tested code samples
---
 solr/solr-ref-guide/build.xml                      |   5 +
 .../src/meta-docs/asciidoc-syntax.adoc             |   8 +
 solr/solr-ref-guide/src/using-solrj.adoc           | 179 +++++++++-------
 .../UsingSolrJRefGuideExamplesTest.java            | 235 +++++++++++++++++++++
 4 files changed, 347 insertions(+), 80 deletions(-)

diff --git a/solr/solr-ref-guide/build.xml b/solr/solr-ref-guide/build.xml
index 6a610b1..1ce3778 100644
--- a/solr/solr-ref-guide/build.xml
+++ b/solr/solr-ref-guide/build.xml
@@ -130,6 +130,11 @@
   <target name="build-init" description="Prepares the build's 'content' dir, copying over src files and transforming *.template files in the process">
     <delete dir="${build.content.dir}" />
     <mkdir dir="${build.content.dir}" />
+
+    <echo>Copying all examples to build directory...</echo>
+    <copy todir="${build.content.dir}">
+      <fileset dir="../solrj/src/test/org/apache/solr/client/ref_guide_examples" />
+    </copy>
     <echo>Copying all non template files from src ...</echo>
     <copy todir="${build.content.dir}">
       <fileset dir="src">
diff --git a/solr/solr-ref-guide/src/meta-docs/asciidoc-syntax.adoc b/solr/solr-ref-guide/src/meta-docs/asciidoc-syntax.adoc
index dd9180e..0161225 100644
--- a/solr/solr-ref-guide/src/meta-docs/asciidoc-syntax.adoc
+++ b/solr/solr-ref-guide/src/meta-docs/asciidoc-syntax.adoc
@@ -72,6 +72,14 @@ Pygments has a long selection of lexers available. You can see the full list at
 
 Ideally, we will have an appropriate lexer to use for all source blocks, but that's not possible. When in doubt, choose `text`, or leave it blank.
 
+==== Importing Code Snippets from Other Files
+
+The build system has the ability to "include" code snippets located in other files.
+
+Snippets are bounded by "tag" comments placed at the start and end of the section you would like to import.  Opening tags look like: `// tag::snippetName[]`.  Closing tags follow the format: `// end::snippetName[]`.  Snippets can be dropped into an adoc file using an `include` directive, following a format: `include::PathToFileWithSnippet[tag=snippetName]`.  Note that when relative paths are provided in this directive, that paths are relative to location of the asciidoc file the include  [...]
+
+For more information on the `include` directive, see the documentation http://asciidoctor.org/docs/user-manual/#include-partial[here].
+
 === Block Titles
 
 Titles can be added to most blocks (images, source blocks, tables, etc.) by simply prefacing the title with a period (`.`). For example, to add a title to the source block example above:
diff --git a/solr/solr-ref-guide/src/using-solrj.adoc b/solr/solr-ref-guide/src/using-solrj.adoc
index efdb7cd..5eea5b7 100644
--- a/solr/solr-ref-guide/src/using-solrj.adoc
+++ b/solr/solr-ref-guide/src/using-solrj.adoc
@@ -18,148 +18,167 @@
 // specific language governing permissions and limitations
 // under the License.
 
-{solr-javadocs}/solr-solrj/[SolrJ] is an API that makes it easy for Java applications to talk to Solr. SolrJ hides a lot of the details of connecting to Solr and allows your application to interact with Solr with simple high-level methods.
+{solr-javadocs}/solr-solrj/[SolrJ] is an API that makes it easy for applications written in Java (or any language based on the JVM) to talk to Solr. SolrJ hides a lot of the details of connecting to Solr and allows your application to interact with Solr with simple high-level methods.  SolrJ supports most Solr APIs, and is highly configurable.
 
-The center of SolrJ is the `org.apache.solr.client.solrj` package, which contains just five main classes. Begin by creating a {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/SolrClient.html[`SolrClient`], which represents the Solr instance you want to use. Then send `SolrRequests` or `SolrQuerys` and get back SolrResponses.
+== Building and Running SolrJ Applications
+
+The SolrJ API ships with Solr, so you do not have to download or install anything else. But you will need to configure your build to include SolrJ and its dependencies.
+
+=== Common Build Systems
 
-`SolrClient` is abstract, so to connect to a remote Solr instance, you'll actually create an instance of either {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/HttpSolrClient.html[`HttpSolrClient`], or {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/CloudSolrClient.html[`CloudSolrClient`]. Both communicate with Solr via HTTP, the difference is that `HttpSolrClient` is configured using an explicit Solr URL, while `CloudSolrClient` is configured using the zkHost S [...]
+Most mainstream build systems greatly simplify dependency management, making it easy to add SolrJ to your project.
 
+For projects built with Ant (using http://ant.apache.org/ivy/[Ivy]), place the following in your `ivy.xml`:
 
-.Single node Solr client
-[source,java]
+[source,xml]
 ----
-String urlString = "http://localhost:8983/solr/techproducts";
-SolrClient solr = new HttpSolrClient.Builder(urlString).build();
+<dependency org="org.apache.solr" name="solr-solrj" rev="x.y.z"/>
 ----
 
-.SolrCloud client
-[source,java]
-----
-// Using a ZK Host String
-String zkHostString = "zkServerA:2181,zkServerB:2181,zkServerC:2181/solr";
-SolrClient solr = new CloudSolrClient.Builder().withZkHost(zkHostString).build();
+For projects built with Maven, place the following in your `pom.xml`:
 
-// Using already running Solr nodes
-SolrClient solr = new CloudSolrClient.Builder().withSolrUrl("http://localhost:8983/solr").build();
+[source,xml]
+----
+<dependency>
+  <groupId>org.apache.solr</groupId>
+  <artifactId>solr-solrj</artifactId>
+  <version>x.y.z</version>
+</dependency>
 ----
 
-Once you have a `SolrClient`, you can use it by calling methods like `query()`, `add()`, and `commit()`.
+For projects built with Gradle, place the following in your `build.gradle`:
 
-== Building and Running SolrJ Applications
+[source,groovy]
+----
+compile group: 'org.apache.solr', name: 'solr-solrj', version: 'x.y.z'
+----
 
-The SolrJ API is included with Solr, so you do not have to download or install anything else. However, in order to build and run applications that use SolrJ, you have to add some libraries to the classpath.
+=== Adding SolrJ to the Classpath Manually
 
-At build time, the examples presented with this section require `solr-solrj-x.y.z.jar` to be in the classpath.
+If you are not using one of the above build system, it's still easy to add SolrJ to your build.
 
-At run time, the examples in this section require the libraries found in the 'dist/solrj-lib' directory.
+At build time, all that is required is the SolrJ jar itself: `solr-solrj-x.y.z.jar`.  To compile code manually that uses SolrJ, use a `javac` command similar to:
 
-The Ant script bundled with this sections' examples includes the libraries as appropriate when building and running.
+[source,bash]
+----
+javac -cp .:$SOLR_HOME/dist/solr-solrj-x.y.z.jar ...
+----
 
-You can sidestep a lot of the messing around with the JAR files by using Maven instead of Ant. All you will need to do to include SolrJ in your application is to put the following dependency in the project's `pom.xml`:
+At runtime, you need a few of SolrJ's dependencies, in addition to SolrJ itself. For convenience, these dependencies are made available in the `dist/solrj-lib` directory.  Run your project with a classpath like:
 
-[source,xml]
+[source,bash]
 ----
-<dependency>
-  <groupId>org.apache.solr</groupId>
-  <artifactId>solr-solrj</artifactId>
-  <version>x.y.z</version>
-</dependency>
+java -cp .:$SOLR_HOME/dist/solrj-lib/*:$SOLR_HOME/dist/solr-solrj-x.y.z.jar ...
 ----
 
 If you are worried about the SolrJ libraries expanding the size of your client application, you can use a code obfuscator like http://proguard.sourceforge.net/[ProGuard] to remove APIs that you are not using.
 
-== Specifying Solr Base URLs
+== SolrJ Overview
 
-Most `SolrClient` implementations (with the notable exception of `CloudSolrClient`) require users to specify one or more Solr base URLs, which the client then uses to send HTTP requests to Solr.  The path users include on the base URL they provide has an effect on the behavior of the created client from that point on.
+For all its flexibility, SolrJ is built around a few simple interfaces.
 
+<<<<<<< ours
 . A URL with a path pointing to a specific core or collection (e.g., `http://hostname:8983/solr/core1`).  When a core or collection is specified in the base URL, subsequent requests made with that client are not required to re-specify the affected collection.  However, the client is limited to sending requests to  that core/collection, and can not send requests to any others.
 . A URL with a generic path pointing to the root Solr path (e.g., `http://hostname:8983/solr`).  When no core or collection is specified in the base URL, requests can be made to any core/collection, but the affected core/collection must be specified on all requests.
+=======
+All requests to Solr are sent by a {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/SolrClient.html[`SolrClient`].  SolrClient's are the main workhorses at the core of SolrJ.  They handle the work of connecting to and communicating with Solr, and are where most of the user configuration happens.
+>>>>>>> theirs
 
-== Setting XMLResponseParser
+Requests are sent in the form of {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/SolrRequest.html[`SolrRequests`], and are returned as {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/SolrResponse.html[`SolrResponses`].
 
-SolrJ uses a binary format, rather than XML, as its default response format. If you are trying to mix Solr and SolrJ versions where one is version 1.x and the other is 3.x or later, then you MUST use the XML response parser. The binary format changed in 3.x, and the two javabin versions are entirely incompatible. The following code will make this change:
+=== Types of SolrClients
 
-[source,java]
-----
-solr.setParser(new XMLResponseParser());
-----
+`SolrClient` has a few concrete implementations, each geared towards a different usage-pattern or resiliency model:
 
-== Performing Queries
+- {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/HttpSolrClient.html[`HttpSolrClient`] - geared towards query-centric workloads, though also a good general-purpose client.  Communicates directly with a single Solr node.
+- {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/LBHttpSolrClient.html[`LBHttpSolrClient`] - balances request load across a list of Solr nodes. Adjusts the list of "in-service" nodes based on node health.
+- {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/CloudSolrClient.html[`CloudSolrClient`] - geared towards communicating with SolrCloud deployments. Uses already-recorded ZooKeeper state to discover and route requests to healthy Solr nodes.
+- {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClient.html[`ConcurrentUpdateSolrClient`] - geared towards indexing-centric workloads.  Buffers documents internally before sending larger batches to Solr.
 
-Use `query()` to have Solr search for results. You have to pass a `SolrQuery` object that describes the query, and you will get back a QueryResponse (from the `org.apache.solr.client.solrj.response` package).
+=== Common Configuration Options
 
-`SolrQuery` has methods that make it easy to add parameters to choose a request handler and send parameters to it. Here is a very simple example that uses the default request handler and sets the query string:
+Most SolrJ configuration happens at the `SolrClient` level.  The most common/important of these are discussed below.  For comprehensive information on how to tweak your `SolrClient`, see the Javadocs for the involved client, and its corresponding builder object.
 
-[source,java]
-----
-SolrQuery query = new SolrQuery();
-query.setQuery(mQueryString);
-----
+==== Base URLs
+Most `SolrClient` implementations (with the notable exception of `CloudSolrClient`) require users to specify one or more Solr base URLs, which the client then uses to send HTTP requests to Solr.  The path users include on the base URL they provide has an effect on the behavior of the created client from that point on.
+
+. A URL with a path pointing to a specific core or collection (e.g. `http://hostname:8983/solr/core1`).  When a core or collection is specified in the base URL, subsequent requests made with that client are not required to re-specify the affected collection.  However, the client is limited to sending requests to  that core/collection, and can not send requests to any others.
+. A URL pointing to the root Solr path (e.g. `http://hostname:8983/solr`).  When no core or collection is specified in the base URL, requests can be made to any core/collection, but the affected core/collection must be specified on all requests.
+
+Generally speaking, if your `SolrClient` will only be used on a single core/collection, including that entity in the path is the most convenient.  Where more flexibility is required, the collection/core should be excluded.
 
-To choose a different request handler, there is a specific method available in SolrJ version 4.0 and later:
+==== Timeouts
+All `SolrClient` implementations allow users to specify the connection and read timeouts for communicating with Solr.  These are provided at client creation time, as in the example below:
 
-[source,java]
+[source,java,indent=0]
 ----
-query.setRequestHandler("/spellCheckCompRH");
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-solrclient-timeouts]
 ----
 
-You can also set arbitrary parameters on the query object. The first two code lines below are equivalent to each other, and the third shows how to use an arbitrary parameter `q` to set the query string:
+When these values are not explicitly provided, SolrJ falls back to using the defaults for the OS/environment is running on.
 
-[source,java]
+== Querying in SolrJ
+`SolrClient` has a number of `query()` methods for fetching results from Solr.  Each of these methods takes in a `SolrParams`,an object encapsulating arbitrary query-parameters.  And each method outputs a `QueryResponse`, a wrapper which can be used to access the result documents and other related metadata.
+
+The following snippet uses a SolrClient to query Solr's "techproducts" example collection, and iterate over the results.
+
+[source,java,indent=0]
 ----
-query.set("fl", "category,title,price");
-query.setFields("category", "title", "price");
-query.set("q", "category:books");
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-query-with-raw-solrparams]
 ----
 
-Once you have your `SolrQuery` set up, submit it with `query()`:
+`SolrParams` has a `SolrQuery` subclass, which provides some convenience methods that greatly simplifies query creation.  The following snippet shows how the query from the previous example can be built using some of the convenience methods in `SolrQuery`:
 
-[source,java]
+[source,java,indent=0]
 ----
-QueryResponse response = solr.query(query);
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-query-with-solrquery]
 ----
 
-The client makes a network connection and sends the query. Solr processes the query, and the response is sent and parsed into a `QueryResponse`.
+== Indexing in SolrJ
+
+Indexing is also simple using SolrJ.  Users build the documents they want to index as instances of `SolrInputDocument`, and provide them as arguments to one of the `add()` methods on `SolrClient`.
 
-The `QueryResponse` is a collection of documents that satisfy the query parameters. You can retrieve the documents directly with `getResults()` and you can call other methods to find out information about highlighting or facets.
+The following example shows how to use SolrJ to add a document to Solr's "techproducts" example collection:
 
-[source,java]
+[source,java,indent=0]
 ----
-SolrDocumentList list = response.getResults();
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-index-with-raw-solrinputdoc]
 ----
 
-== Indexing Documents
+CAUTION: The indexing examples above are intended to show syntax.  For brevity, they break several Solr indexing best-practices.  Under normal circumstances, documents should be indexed in larger batches, instead of one at a time.  It is also suggested that Solr administrators commit documents using Solr's autocommit settings, and not using explicit `commit()` invocations.
 
-Other operations are just as simple. To index (add) a document, all you need to do is create a `SolrInputDocument` and pass it along to the `SolrClient` 's `add()` method. This example assumes that the SolrClient object called 'solr' is already created based on the examples shown earlier.
+== Java Object Binding
+While the `UpdateResponse` and `QueryResponse` interfaces that SolrJ provides are useful, it is often more convenient to work with domain-specific objects that can more easily be understood by your application.  Thankfully, SolrJ supports this by implicitly converting documents to and from any class that has been specially marked with {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj//beans/Field.html[`Field`] annotations.
 
-[source,java]
-----
-SolrInputDocument document = new SolrInputDocument();
-document.addField("id", "552199");
-document.addField("name", "Gouda cheese wheel");
-document.addField("price", "49.99");
-UpdateResponse response = solr.add(document);
+Each instance variable in a Java object can be mapped to a corresponding Solr field, using the `Field` annotation.  The Solr field shares the name of the annotated variable by default, however, this can be overridden by providing the annotation with an explicit field name.
 
-// Remember to commit your changes!
+The example snippet below shows an annotated `TechProduct` class that can be used to represent results from Solr's "techproducts" example collection.
 
-solr.commit();
+[source,java,indent=0]
+----
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-techproduct-value-type]
 ----
 
-=== Uploading Content in XML or Binary Formats
-
-SolrJ lets you upload content in binary format instead of the default XML format. Use the following code to upload using binary format, which is the same format SolrJ uses to fetch results. If you are trying to mix Solr and SolrJ versions where one is version 1.x and the other is 3.x or later, then you MUST stick with the XML request writer. The binary format changed in 3.x, and the two javabin versions are entirely incompatible.
+Application code with access to the annotated `TechProduct` class above can index `TechProduct` objects directly without any conversion, as in the example snippet below:
 
-[source,java]
+[source,java,indent=0]
 ----
-solr.setRequestWriter(new BinaryRequestWriter());
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-index-bean-value-type]
 ----
 
-=== Using the ConcurrentUpdateSolrClient
+Similarly, search results can be converted directly into bean objects using the `getBeans()` method on `QueryResponse`:
 
-When implementing java applications that will be bulk loading a lot of documents at once, {solr-javadocs}/solr-solrj/org/apache/solr/client/solrj/impl/ConcurrentUpdateSolrClient.html[`ConcurrentUpdateSolrClient`] is an alternative to consider instead of using `HttpSolrClient`. The `ConcurrentUpdateSolrClient` buffers all added documents and writes them into open HTTP connections. This class is thread safe. Although any SolrClient request can be made with this implementation, it is only r [...]
+[source,java,indent=0]
+----
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-query-bean-value-type]
+----
 
-== EmbeddedSolrServer
+== Other APIs
+SolrJ allows more than just querying and indexing.  It supports all of Solr's APIs.  Accessing Solr's other APIs is as easy as finding the appropriate request object, providing any necessary parameters, and passing it to the `request()` method of your `SolrClient`.  `request()` will return a `NamedList`: a generic object which mirrors the hierarchical structure of the JSON or XML returned by their request.
 
-The {solr-javadocs}/solr-core/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.html[`EmbeddedSolrServer`] class provides an implementation of the `SolrClient` client API talking directly to an micro-instance of Solr running directly in your Java application. This embedded approach is not recommended in most cases and fairly limited in the set of features it supports – in particular it can not be used with <<solrcloud.adoc#solrcloud,SolrCloud>> or <<index-replication.adoc#index-re [...]
+The example below shows how SolrJ users can call the CLUSTERSTATUS API of SolrCloud deployments, and manipulate the returned `NamedList`:
 
-For information on how to use `EmbeddedSolrServer` please review the SolrJ JUnit tests in the `org.apache.solr.client.solrj.embedded` package of the Solr source release.
+[source,java,indent=0]
+----
+include::UsingSolrJRefGuideExamplesTest.java[tag=solrj-other-apis]
+----
diff --git a/solr/solrj/src/test/org/apache/solr/client/ref_guide_examples/UsingSolrJRefGuideExamplesTest.java b/solr/solrj/src/test/org/apache/solr/client/ref_guide_examples/UsingSolrJRefGuideExamplesTest.java
new file mode 100644
index 0000000..a988540
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/client/ref_guide_examples/UsingSolrJRefGuideExamplesTest.java
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.solr.client.ref_guide_examples;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.beans.Field;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.CollectionAdminResponse;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.UpdateResponse;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.util.ExternalPaths;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Example SolrJ usage.
+ *
+ * Snippets surrounded by "tag" and "end" comments are extracted and used in the Solr Reference Guide.
+ */
+public class UsingSolrJRefGuideExamplesTest extends SolrCloudTestCase {
+
+  private static final int NUM_INDEXED_DOCUMENTS = 3;
+  private static final int NUM_LIVE_NODES = 1;
+
+  @BeforeClass
+  public static void setUpCluster() throws Exception {
+    configureCluster(NUM_LIVE_NODES)
+        .addConfig("conf", new File(ExternalPaths.TECHPRODUCTS_CONFIGSET).toPath())
+        .configure();
+
+    CollectionAdminResponse response = CollectionAdminRequest.createCollection("techproducts", "conf", 1, 1)
+        .process(cluster.getSolrClient());
+  }
+
+  @Before
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    final SolrClient client = getSolrClient();
+
+    final List<TechProduct> products = new ArrayList<TechProduct>();
+    products.add(new TechProduct("1","Fitbit Alta"));
+    products.add(new TechProduct("2", "Sony Walkman"));
+    products.add(new TechProduct("3", "Garmin GPS"));
+
+    client.addBeans("techproducts", products);
+    client.commit("techproducts");
+  }
+
+  @After
+  @Override
+  public void tearDown() throws Exception {
+    super.tearDown();
+
+    final SolrClient client = getSolrClient();
+    client.deleteByQuery("techproducts", "*:*");
+    client.commit("techproducts");
+  }
+
+  @Test
+  public void queryWithRawSolrParamsExample() throws Exception {
+    // tag::solrj-query-with-raw-solrparams[]
+    final SolrClient client = getSolrClient();
+
+    final Map<String, String> queryParamMap = new HashMap<String, String>();
+    queryParamMap.put("q", "*:*");
+    queryParamMap.put("fl", "id, name");
+    MapSolrParams queryParams = new MapSolrParams(queryParamMap);
+
+    final QueryResponse response = client.query("techproducts", queryParams);
+    final SolrDocumentList documents = response.getResults();
+
+    assertEquals(NUM_INDEXED_DOCUMENTS, documents.getNumFound());
+    for(SolrDocument document : documents) {
+      assertTrue(document.getFieldNames().contains("id"));
+      assertTrue(document.getFieldNames().contains("name"));
+    }
+    // end::solrj-query-with-raw-solrparams[]
+  }
+
+  @Test
+  public void queryWithSolrQueryExample() throws Exception {
+    final int numResultsToReturn = 1;
+    final SolrClient client = getSolrClient();
+
+    // tag::solrj-query-with-solrquery[]
+    final SolrQuery query = new SolrQuery("*:*");
+    query.addField("id");
+    query.addField("name");
+    query.setRows(numResultsToReturn);
+    // end::solrj-query-with-solrquery[]
+
+    final QueryResponse response = client.query("techproducts", query);
+    final SolrDocumentList documents = response.getResults();
+
+    assertEquals(NUM_INDEXED_DOCUMENTS, documents.getNumFound());
+    assertEquals(numResultsToReturn, documents.size());
+    for(SolrDocument document : documents) {
+      assertTrue(document.getFieldNames().contains("id"));
+      assertTrue(document.getFieldNames().contains("name"));
+    }
+  }
+
+  @Test
+  public void indexWithSolrInputDocumentExample() throws Exception {
+    // tag::solrj-index-with-raw-solrinputdoc[]
+    final SolrClient client = getSolrClient();
+
+    final SolrInputDocument doc = new SolrInputDocument();
+    doc.addField("id", UUID.randomUUID().toString());
+    doc.addField("name", "Amazon Kindle Paperwhite");
+
+    final UpdateResponse updateResponse = client.add("techproducts", doc);
+    // Indexed documents must be committed
+    client.commit("techproducts");
+    // end::solrj-index-with-raw-solrinputdoc[]
+
+    assertNumDocuments(NUM_INDEXED_DOCUMENTS + 1);
+  }
+
+  @Test
+  public void indexBeanValueTypeExample() throws Exception {
+    // tag::solrj-index-bean-value-type[]
+    final SolrClient client = getSolrClient();
+
+    final TechProduct kindle = new TechProduct("kindle-id-4", "Amazon Kindle Paperwhite");
+    final UpdateResponse response = client.addBean("techproducts", kindle);
+
+    client.commit("techproducts");
+    // end::solrj-index-bean-value-type[]
+
+    assertNumDocuments(NUM_INDEXED_DOCUMENTS + 1);
+  }
+
+  @Test
+  public void queryBeanValueTypeExample() throws Exception {
+    // tag::solrj-query-bean-value-type[]
+    final SolrClient client = getSolrClient();
+
+    final SolrQuery query = new SolrQuery("*:*");
+    query.addField("id");
+    query.addField("name");
+
+    final QueryResponse response = client.query("techproducts", query);
+    final List<TechProduct> products = response.getBeans(TechProduct.class);
+    // end::solrj-query-bean-value-type[]
+
+    assertEquals(NUM_INDEXED_DOCUMENTS, products.size());
+    for (TechProduct product : products) {
+      assertFalse(product.id.isEmpty());
+      assertFalse(product.name.isEmpty());
+    }
+  }
+
+  @Test
+  public void otherSolrApisExample() throws Exception {
+    // tag::solrj-other-apis[]
+    final SolrClient client = getSolrClient();
+
+    final SolrRequest request = new CollectionAdminRequest.ClusterStatus();
+
+    final NamedList<Object> response = client.request(request);
+    final NamedList<Object> cluster = (NamedList<Object>) response.get("cluster");
+    final List<String> liveNodes = (List<String>) cluster.get("live_nodes");
+
+    assertEquals(NUM_LIVE_NODES, liveNodes.size());
+    // end::solrj-other-apis[]
+  }
+
+  private SolrClient getSolrClient() {
+    return cluster.getSolrClient();
+  }
+
+  private SolrClient getTechProductSolrClient() {
+    // tag::solrj-solrclient-timeouts[]
+    final String solrUrl = "http://localhost:8983/solr";
+    return new HttpSolrClient.Builder(solrUrl)
+        .withConnectionTimeout(10000)
+        .withSocketTimeout(60000)
+        .build();
+    // end::solrj-solrclient-timeouts[]
+  }
+
+  private void assertNumDocuments(int expectedNumResults) throws Exception {
+    final QueryResponse queryResponse = getSolrClient().query("techproducts", new SolrQuery("*:*"));
+    assertEquals(expectedNumResults, queryResponse.getResults().getNumFound());
+  }
+
+  // tag::solrj-techproduct-value-type[]
+  public static class TechProduct {
+    @Field public String id;
+    @Field public String name;
+
+    public TechProduct(String id, String name) {
+      this.id = id;  this.name = name;
+    }
+
+    public TechProduct() {}
+  }
+  // end::solrj-techproduct-value-type[]
+
+}