Panl Cookbook

The type of the Solr field and Panl type will determine the configuration options available and the information that is contained within the response object.

The Panl JSON response attempts to provide the implementer with enough information to determine the rendering to the interface, rather than hard-coding Solr field names and deciding on how they should be handled.

In this chapter, some 'recipes' for how to implement various faceted search queries that have been seen on other websites.

Notes: There are links to websites in this chapter, with the changing nature of the web and constant updates, by the time you read this book and/or click on the links, they may very well have changed.

SEO Friendlier Canonical URLs

Returning to the previous Amazon example[49] for the rOtring Rapid Pro Mechanical pencil, the URL is as follows:

https://www.amazon.com/rOtring-1904260-Rapid-Mechanical-Pencil/dp/B0055ZV8LK

Deconstructing the URL:

With the only important part (for the Amazon back-end servers) being the product identifier which is B0055ZV8LK, and the URL of

https://www.amazon.com/dp/B0055ZV8LK/

Will link to exactly the same page.

To replicate this with the Panl server, the pencil that is referenced by the above is:

http://localhost:8181/panl-results-viewer/mechanical-pencils/default/Manufactured%20by%20Rotring%20Company/Rapid%20PRO/rotring/bNq/ 

Which is the search query that will only return one result:



Image: The Single result for the search query.

Note at the bottom the id Solr field (with a LPSE code of i) with the value of 50 - which is the document id for the Solr result, which was generated from the Synapticloop database.  This ID is the unique reference to the Solr document, and the URL:

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/50/i/

With a passthrough parameter set (in the example this is 'z') then any string could be added to the URL and the LPSE included, for example:

 http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/rOtring-1904260-Rapid-Mechanical-Pencil/50/zi/

Configuration Details

In the <panl_collection_url>.panl.properties file ensure the following:

  1. The panl.param.passthrough property is set (in the examples this is set to 'z')
    This will enable the functionality to build the SEO friendlier URLs
  2. The panl.param.passthrough.canonical is set to true
    This will ensure that the passthrough parameter is used to generate the canonical URL
  3. The id Solr field is configured as a Panl facet, i.e.: panl.facet.i=id
    This will enable Solr to look this up as a facet and pass the value to it
  4. The LPSE code (i.e. 'i') for this facet is included in the panl.lpse.order property
    This will ensure that Panl has enabled the Solr field to be faceted upon and the value will be passed through to the Solr server (as opposed to ignoring it).
  5. The Solr Field name (Panl LPSE code - 'id') is included in the panl.lpse.ignore property
    This will ensure that Panl does not include this LPSE code in the facetable fields (which are presented on the left hand side on the in-build Panl results viewer web app).

The mechanical-pencils.panl.properties file snippets for the above:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

...

panl.param.passthrough=z

panl.param.passthrough.canonical=true

...

panl.facet.i=id

panl.name.i=Id

panl.type.i=solr.StrField

...

panl.lpse.order=z,b,N,m,W,G,C,L,D,h,I,Z,9,w,i,s,p,n,o,q

...

panl.lpse.ignore=id

...

Tips: If the unique identifier LPSE code is only going to be used for this purpose (i.e. canonical URLs), then placing it towards the end of the LPSE order is recommended.

Recommendation

When attempting to use a passthrough parameter for a canonical URL, it may be better to have a service that automatically generates the canonical URL, rather than relying on passthrough parameters.  For example, for the mechanical pencil above, a service that generates and concatenates the brand name, model number, model name and associated colour from the unique identifier may be a better choice than using the Panl server.

This will ensure that the passthrough parameter canonical URL is generated correctly and uniquely, that way, no matter the passthrough parameter URL that is requested, the actual canonical URL remains the same.

IMPORTANT: Panl generates SEO friendlier URLs throughout the search journey and using the Panl server to generate the canonical URL for a single product may have some downsides.  Remember that Panl is disassociated from the underlying data, so for a single product (as in the above example) the following URLs will all link to the same results (which will reduce the efficacy of the SEO):

BOOLEAN Facets

Apart from the boolean true/false value replacement, the BOOLEAN facet can be designated as a checkbox.

Displaying a BOOLEAN facet as a checkbox

This is only useful when you want to select only one of the true/false values or no value (i.e. both).

Even though a BOOLEAN facet has only two values, there are actually three states that a BOOLEAN facet can have:

  1. 'True' selected - only those results with a true value will be returned
  2. 'False' selected - only those results with a false value will be returned
  3. Not selected - all results are returned which have either a true or false value.
    There is an additional state in which the document does not have any value assigned to this facet

Using a checkbox is different from using the in-built Panl functionality in that you may select 'true', 'false' or remove the selection.  In the case of a checkbox, you will only be able to select one of the true or false values, or select neither.

This is a good use case if you want to highlight only one of the values.  

True Value BOOLEAN Facet Checkbox Example

As an example shopping sites may have a 'Speedy' delivery checkbox, which will filter those results which are available for speedy delivery, however the shopping site does not wish to highlight the results that do not qualify for speedy delivery.  Hence the facet may be selected as either 'True' or no facet value at all.

False Value BOOLEAN Facet Checkbox Example

As an example, shopping sites may have items which are on backorder, thus making them unavailable for immediate delivery, but still deliverable once the backorder has been fulfilled.  For the user experience, you may wish to present a 'Exclude items on backorder' checkbox.  In effect this will set the boolean value for 'backorder' to 'false', if unchecked then all items will be shown, both those on backorder, and those not on backorder'.

In either of the above cases, any BOOLEAN facet can be turned into a checkbox, provided that you understand how this impacts the facet selection.

For the implementation, either the LPSE code, or the Solr field name must be known ahead of time.  This does tie the implementation to the data - (there is an additional piece of functionality which is under consideration to be able to set a 'checkbox' property on a BOOLEAN Facet), in the meantime, the implementation is as follows:

Using the contrived example of:

  • Solr field name - JSON key name facet_name = in_built_eraser
  • LPSE code - JSON key name panl_code = I

If the facet with the above Solr field name or LPSE code:

  • Is in the panl.active.facets JSON Array, then the checkbox should be selected.

    To deselect the checkbox, use the
    remove_uri JSON property.
  • Is in the panl.available.facets JSON Array, then render a checkbox with the value deselected.  

    To select the checkbox, use the
    uris.before and uris.after in conjunction with the searching through the values array for the value key equalling either "true" of "false" and use the value of the encoded key.

RANGE Facets

'Reverse' star Ratings

Many sites allow ratings of items (and comments), however, rather than searching for a rating between two values, they only permit a variable start range and upwards.  For the URL.

https://www.ryman.co.uk/stationery/pens/ballpoint?bv_rating=[2+TO+*]

The facet that is rendered:



Image: Star ratings with links a number of stars or upwards

Example Properties

To generate this example, the following <panl_collection_url>.panl.properties file could be used.

01

02

03

04

05

06

07

08

09

10

11

panl.facet.r=rating

panl.name.r=Ratings

panl.type.r=solr.FloatPointField

panl.prefix.r=Rating from:

panl.infix.r=-star-and-

panl.range.facet.r=true

panl.range.min.r=1

panl.range.max.r=5

panl.range.max.value.r=UP

panl.range.min.wildcard.r=false

panl.range.max.wildcard.r=true

panl.range.suppress.r=true

To generate the links, iterate from the panl.range.min.r property value to the panl.range.max.r property value and generate the link of

panl.prefix.r + <value> + panl.infix.r + panl.range.max.value

With the appropriate before and after links from the JSON response.

From the JSON response object, the above link generation would become:

uris.before + <value> + uris.during + uris.after_max_value

Which would generate a URL which would look like:

/Rating from:1-star-and-UP/r-/

As a side note:  the above image was taken from the Ryman's UK site.  The URL looks suspiciously like an Apache Solr URL - you can edit the URL to find ratings between 0 and 2, or ratings up to 3.  

If you put in an invalid range value - e.g. [gh+TO+jk] - the search results will say that it is down for maintenance, a lack of protection which should have been caught before getting to the search results and which Panl handles nicely.

REGULAR Facets

Condensed Multivalued Paths

This is especially useful where there is a prefix and/or a suffix that gets applied to every single facet value that is selected.  

Condensing the path is only available on REGULAR facets that are defined as multivalued in the Solr schema (i.e. on the XML field definition there is an attribute and value of multiValued="true") AND have the panl.multivalue.<lpse_code>=true property set in the <panl_collection_url>.panl.properties file.

In this example, the original mechanical-pencils.panl.properties file has been edited so that the Colours facet has a prefix of 'Colour:':

Example Properties - Original

01

02

03

04

05

panl.facet.W=colours

panl.name.W=Colours

panl.prefix.W=Colour:

panl.multivalue.W=true

panl.type.W=solr.StrField


Base URL:

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname 
(0 characters - not including the CaFUP)

One Facet, adding 'Black'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/W/ 
(15 characters - not including the CaFUP)

Two Facets, adding 'Blue'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/Colour:Blue/WW/ 
(28 characters - not including the CaFUP)

Three Facets, adding 'Red'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/Colour:Blue/Colour:Red/WWW/ 
(40 characters - not including the CaFUP)

Four Facets, adding 'Green'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/Colour:Blue/Colour:Red/Colour:Green/WWWW/ 
(54 characters - not including the CaFUP)

Five Facets, adding 'Yellow'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/Colour:Blue/Colour:Green/Colour:Red/Colour:Yellow/WWWWW/ 
(69 characters - not including the CaFUP)

Six Facets, adding 'Brown'

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/Colour:Black/Colour:Blue/Colour:Green/Colour:Red/Colour:Yellow/Colour:Brown/WWWWWW/ 
(83 characters - not including the CaFUP)

The  above URL will select pencil models that have colours in Black, Blue, Green, Red, Yellow, and Brown (There is only one result).  

Note the 6 'W' LPSE codes.

To condense the LPSE URL, configure Panl to have a multi value separator

Example Properties - Condensed

01

02

03

04

05

06

panl.facet.W=colours

panl.name.W=Colours

panl.prefix.W=Colours:

panl.multivalue.W=true

panl.type.W=solr.StrField

panl.multivalue.separator.W=,


In the above configuration, note that the prefix is now '
Colours:' (plural) as opposed to the prefix of 'Colour:' in the previous configuration.  The impact of this is that the first facet will increase the LPSE URL length by 1, which has less of an impact as more facets are added.

Base URL:

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname   
(0 characters - not including the CaFUP)

One Facet, adding 'Black'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black/W/
(16 characters - not including the CaFUP)

Two Facets, adding 'Blue'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black,Blue/W/
(21 characters - not including the CaFUP)

Three Facets, adding 'Red'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black,Blue,Red/W/
(25 characters - not including the CaFUP)

Four Facets, adding 'Green'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black,Blue,Red,Green/W/ 
(31 characters - not including the CaFUP)

Five Facets, adding 'Yellow'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black,Blue,Green,Red,Yellow/W/ 
(38 characters - not including the CaFUP)

Six Facets, adding 'Brown'

http://localhost:8181/panl-results-viewer/mechanical-pencils-multi-separator/brandandname/Colours:Black,Blue,Green,Red,Yellow,Brown/W/
(44 characters - not including the CaFUP)

Which is slightly more readable, and saves space on the URL.

If the LPSE code is multivalued enabled (i.e the panl.multivalue.separator.<lpse_code> exists and is not an empty string), then the generated LPSE URLs will automatically include the correct information.

When rendering the value that the end user will see, you may choose either the encoded (which will include the prefix), or the encoded_multi (which will preclude the prefix) JSON key's value.

For the above example the compression rate - i.e. the ratio of condensed to normal as a percentage is as follows:

URL

Normal

Condensed

% Compression

Base URL

0

0

N/A

1 Colour

15

16

106%

2 Colours

28

21

75.0%

3 Colours

40

25

62.5%

4 Colours

54

31

57.4%

5 Colours

69

38

55.1%

6 Colours

83

44

53.0%


In the above table, remember that the condensed figure has a longer suffix that is applied to the values, hence the slight expansion for the addition of 1 colour.

OR Facets

Condensed OR Facets

Like the condensed multivalued facets, an OR Facet can have its LPSE path condensed by using only one prefix and one suffix irrespective of how many values are used within the URI.

In this example, the mechanical-pencils-or.panl.properties file for the 'brand' facet configuration is below:

Example Properties - Original

01

02

03

04

05

06

panl.facet.b=brand

panl.or.facet.b=true

panl.or.always.b=true

panl.prefix.b=Manufactured by

panl.name.b=Brand

panl.type.b=solr.StrField


The above configures the brand facet to have a prefix of '
Manufactured by ' without any suffix.  When adding facets to the query, the URL quickly grows with the prefix being added to each facet value:

The landing page:

http://localhost:8181/panl-results-viewer/mechanical-pencils-or/brandandname
(0 characters - not including the CaFUP)

Adding the brand facet value 'Staedtler':

http://localhost:8181/panl-results-viewer/mechanical-pencils-or/brandandname/Manufactured by Staedtler/b/ 
(28 characters  - not including the CaFUP)

Adding another brand facet value of 'Mitsubishi'

http://localhost:8181/panl-results-viewer/mechanical-pencils-or/brandandname/Manufactured by Staedtler/Manufactured by Mitsubishi/bb/
(28 characters  - not including the CaFUP)

Adding a third brand facet value of 'Hightide Penco'

http://localhost:8181/panl-results-viewer/mechanical-pencils-or/brandandname/Manufactured by Mitsubishi/Manufactured by Staedtler/Manufactured by Hightide Penco/bbb/
(88 characters  - not including the CaFUP)

With a condensed LPSE path configuration (from the mechanical-pencils-or-separator.panl.properties file):

Example Properties - Condensed

01

02

03

04

05

06

07

08

panl.facet.b=brand

panl.or.facet.b=true

panl.or.always.b=true

panl.or.separator.b=, or

panl.prefix.b=Manufactured by

panl.suffix.b=\ Co.

panl.name.b=Brand

panl.type.b=solr.StrField


The above configures the brand facet to have a prefix of '
Manufactured by ' (note the trailing space) and a suffix of ' Co.' (note the leading space) and an OR separator of ', or '.  When adding facets to the query, the URL will now have:

  • Only one prefix
  • Only one suffix
  • Only one LPSE code

The landing page:

http://localhost:8181/panl-results-viewer/mechanical-pencils-or-separator/brandandname
(0 characters  - not including the CaFUP)

Adding the brand facet value 'Staedtler':

http://localhost:8181/panl-results-viewer/mechanical-pencils-or-separator/brandandname/Manufactured by Staedtler Co./b/
(32 characters  - not including the CaFUP)

Adding another brand facet value of 'Mitsubishi'

http://localhost:8181/panl-results-viewer/mechanical-pencils-or-separator/brandandname/Manufactured by Staedtler, or Mitsubishi Co./b/
(47 characters  - not including the CaFUP)

Adding a third brand facet value of 'Hightide Penco'

http://localhost:8181/panl-results-viewer/mechanical-pencils-or-separator/brandandname/Manufactured by Mitsubishi, or Staedtler, or Hightide Penco Co./b/
(66 characters  - not including the CaFUP)

For the above example the compression rate - i.e. the ratio of condensed to normal as a percentage is as follows:

URL

Normal

Condensed

% Compression

Base URL

0

0

N/A

1 Brand

28

32

114%

2 Brand

56

47

83.9%

3 Brands

88

66

75%


In the above table, remember that the condensed figure has an additional prefix that is applied to the values, hence the slight expansion for the addition of 1 brand.

Analysed Facets (think Word Clouds)

Whilst Word Clouds have probably gone out of fashion, there is still value in being able to facet on individual words within a document.  The example that is used here is a subset of the text from the Book "Moby Dick" by Herman Melville - downloaded from the Project Gutenberg Website (https://www.gutenberg.org/cache/epub/2701/pg2701.txt) and is located in the src/test/resources/sample/book/data directory of the project.  The subsert is the first 14 chapters of the book.

Implementation Details

Step 1. Create the Solr Schema managed schema

The managed schema file for Solr is very simple in this example (a copy of which can be found here: src/test/resources/sample/book/solr/managed-schema.xml) - a snippet of which is below.

01

02

03

04

05

06

07

08

09

10

11

12

<?xml version="1.0" encoding="UTF-8" ?>

<schema name="book" version="1.6">

  <field name="_version_" type="plong" indexed="false" stored="false"/>

  <field name="id" type="string" stored="true" required="true" ↩
        multiValued="false" />

  <field name="contents" type="text_general" indexed="true" stored="true" ↩
        multiValued="false" />

  <uniqueKey>id</uniqueKey>

  ...

</schema>

There is only one defined field for the contents - which is set to be of type text_general which will be analysed, and used as a facet.

Step 2. Generate the Panl Properties file

From the schema that was created in step 1 above, the Panl generator was used to output the panl.properties file and the book.panl.properties file.  

*NIX

Command(s)

bin\panl generate ↩

  -schema src/test/resources/sample/book/solr/managed-schema.xml ↩

  -properties src/test/resources/sample/book/panl/panl.properties ↩

  -overwrite true


Windows

Command(s)

bin/panl generate ↩

  -schema src\test\resources\sample\book\solr\managed-schema.xml ↩

  -properties src\test\resources\sample\book\panl\panl.properties ↩

  -overwrite true

The above generated both the files that were required.

Step 3. Edit the book.panl.properties file

Only one field was defined from the schema

01

02

03

04

05

# <field "indexed"="true" "stored"="true" "name"="contents" "type"="text_general" ↩
        "multiValued"="false" />

# This configuration can be either a field or a facet as it is indexed in Solr

panl.facet.c=contents

panl.name.c=Contents

panl.type.c=solr.TextField

And will be left as is

Step 4: Upload the schema to Solr

*NIX

Command(s)

bin/solr create  ↩
 -c book  ↩
 -d src/test/resources/sample/book/solr  ↩

  -sh 2  ↩

  -rf 2


Windows

Command(s)

bin\solr create  ↩
 -c book  ↩
 -d src\test\resources\sample\book\solr  ↩

  -sh 2  ↩

  -rf 2


Step 5: Index the data

As we wanted to index each word, a simple indexer was created, uploading the book paragraph by paragraph.  As the text file does not have an id (which is required), a simple indexer was written with a simple unique id generated for each paragraph added.

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

package book;

import org.apache.commons.io.FileUtils;

import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;

import org.apache.solr.client.solrj.impl.CloudSolrClient;

import org.apache.solr.common.SolrInputDocument;

import java.io.File;

import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.util.List;

import java.util.StringTokenizer;

public class Main {

  public static void main(String[] args) {

    CloudSolrClient client = new CloudHttp2SolrClient.Builder(

        List.of("http://localhost:8983/solr/")).build();

    try {

      String txtContents = FileUtils.readFileToString(

      new File("src/test/resources/sample/book/data/herman-melville-moby-dick.txt"),

      StandardCharsets.UTF_8);

      StringTokenizer stringTokenizer = new StringTokenizer(txtContents, "\n");

      int i = 0;

      while (stringTokenizer.hasMoreTokens()) {

        SolrInputDocument doc = new SolrInputDocument();

        String token = stringTokenizer.nextToken();

        if(token.isBlank()) {

          continue;

        }

        doc.addField("id", i++);

        doc.addField("contents", token);

        client.add("book", doc);

        if (i % 1000 == 0) {

          client.commit("book");

        }

      }

      client.commit("book");

    } catch(Exception ignored) {

    } finally {

      try {

        client.close();

      } catch (IOException ignored) {

      }

    }

  }

}

Step 6. Start the Panl server

*NIX

Command(s)

bin/panl server ↩

  -properties src/test/resources/sample/book/panl/panl.properties


Windows

Command(s)

bin\panl server ↩

  -properties src\test\resources\sample\book\panl\panl.properties

And browse the documents

http://localhost:8181/panl-results-viewer/book/empty/

This contents facet will show:

  • the (1397)
  • and (798)
  • a (711)
  • of (672)
  • to (555)
  • in (457)
  • i (392)
  • ...

Which has far to many small filler words, so they will need to be removed.

Step 7. Update the Solr Stop words file

In the src/test/resources/sample/book/solr/stopwords.txt file, add the stop words that you wish to filter out - the src/test/resources/sample/book/solr/stopwords-example.txt file has the words that were chosen for this implementation and may require more.

Step 8. Re-create the Solr Collection and Re-index the Data

For this implementation, the Solr Admin console will be used as an easy and straightforward way to delete a collection.

  1. Open the Solr Admin console (http://localhost:7574/solr/#/)
  2. Click on the Collections link which will take you to this page -
    http://localhost:7574/solr/#/~collections 
  3. Click on the book collection
  4. Click Delete Collection
  5. Enter the collection name (i.e. "book")
  6. Click Delete

Now

  1. Re-create the Solr collection
  2. Re-run the indexer

Using Panl for Dynamic Navigation Menus

Rather than having a separate configuration for the navigation, Panl can be used to drive the navigation menus.

For example, generating links to brand pages, or brand search results, create

Use the empty FieldSet (as you won't be rendering any of the documents) and set the panl.lpse.order=z,b,s,p,n,o,q to only include the b LPSE code (which is the brand name).

Note: In the above example, you will still need to include the panl.params (i.e. z,s,p,n,o,q) however these will be unused for the navigation.

01

02

03

04

05

06

07

08

09

10

11

12

13

14

# <field "indexed"="true" "stored"="true" "name"="brand" "type"="string" ↩

         "multiValued"="false" />

panl.facet.b=brand

panl.or.facet.b=false

panl.range.facet.b=false

panl.name.b=Brand

panl.type.b=solr.StrField

panl.prefix.b=Manufactured by

panl.suffix.b=\ Company

panl.extra.b={ "short_value": true }

panl.facetsort.b=index

...

panl.lpse.order=z,b,s,p,n,o,q

In the above properties, the facetsort property is set to index so that the results are returned in alphabetical order

Notes: It is a good idea to cache the response as in most instances, the navigation shouldn't change too frequently.


Colour Swatches and Sort Names

Rather than within the UI code, searching through the various Solr facet names and then implementing.  Panl allows adding additional information through configuration (which is added to the Panl response object under the  'extra' JSON key) this enables the code to be decoupled from the Solr collection and field names.

In the sample directory (i.e. the sample/panl/mechanical-pencils/ directory) the mechanical-pencils-extra.panl.properties file configures this CaFUP to include an extra JSON object to pass additional information through to the front end UI.  

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

# <field "indexed"="true" "stored"="true" "name"="brand" "type"="string" ↩

         "multiValued"="false" />

panl.facet.b=brand

panl.or.facet.b=false

panl.range.facet.b=false

panl.name.b=Brand

panl.type.b=solr.StrField

panl.prefix.b=Manufactured by

panl.suffix.b=\ Company

panl.extra.b={ "short_value": true }

panl.facetsort.b=index

...

# <field "indexed"="true" "stored"="true" "name"="colours" "type"="string" ↩

         "multiValued"="true" />

panl.facet.W=colours

panl.name.W=Colours

panl.multivalue.W=true

panl.type.W=solr.StrField

panl.extra.W={ "swatch": true }

Which will add this JSON object (see Lines 9 and 20) in both the available and active facets Panl objects for their respective Solr facets.

The in-build Panl Results Viewer Web App uses this information to change the rendering.  In Line 9 the short_value property is used to render the value of the facet, rather than the value_encoded.  In Line 20 the swatch property is used to render colour swatches in addition to the name.  The below URL and image shows the rendering:

http://localhost:8181/panl-results-viewer/mechanical-pencils-extra/brandandname/

Which renders:



Image: The Panl results with the extra JSON object driving the rendering of the facets.

Without the extra JSON object, the rendering of the URL remains as per the previous examples in the book.

http://localhost:8181/panl-results-viewer/mechanical-pencils/brandandname/



Image: The Panl results viewer, without the rendering hints provided by the extra JSON object.

Number Of Results Per Page

In the in-built Panl Results Viewer web app, the number of results per page that can be selected is hard-coded to 3, 5, or 10.  Should you wish to drive the values that are displayed on the page, then you can set additional information through the panl.properties file.

For an example, the

 PANL_INSTALL_DIRECTORY\sample\panl\mechanical-pencils-extra\panl.properties 

file defines a property of

panl.server.extra={ "num_per_page": [ 5, 10, 20 ] }

Which will return this property value in every response for the designated CaFUPs under the JSON key panl.extra.

01

02

03

04

05

06

07

08

09

10

11

{

  "panl" {

  ...

  "extra": {

    "num_per_page": [ 5, 10, 20 ]

  }

  ...

}

This value can be overridden on a per collection basis by setting a property key of panl.collection.extra which  will send through the extra JSON object for that CaFUP only.

The file

PANL_INSTALL_DIRECTORY\sample\panl\mechanical-pencils-extra\mechanical-pencils-extra.panl.properties 

defines a property of

panl.collection.extra={ "num_per_page": [ 10, 20 ] }

Which overrides the server extra above and only returns the two values in the array.

01

02

03

04

05

06

07

08

09

10

11

{

  "panl" {

  ...

  "extra": {

    "num_per_page": [ 10, 20 ]

  }

  ...

}

More Like This Functionality

The More Like This (MLT) functionality in Solr returns documents that are similar to a specific document in their result list.  It does this by using terms from the unique specific document to find similar other documents in the index.

Within the Solr server, there are three implementations available, namely:

  1. The MoreLikeThis Request Handler, (This is the recommended implementation)
  2. The MoreLikeThis Search Component, and
  3. The MoreLikeThis Query Parser (using either internal, or external content)

There are three ways to implement the More Like This (MLT) functionality, the Panl Server only supports two of these methods.

The Panl server only supports the first and third methods (the third method only performs on internal content, not external content).  There is an additional Query Parser that allows external content which is also not supported by the Panl server.

For More Like This requests that are passed to a replica shard, the Solr server will not return any results.  Consequently, Panl adds a Solr parameter of shards=shard1 and will attempt to retry the connection if it does not work up to 5 times.  There is a failure rate of up to 10% so be warned.

IMPORTANT: Within the Solr server (at least 9.10.0-slim version that is being used) there is a 'feature'[50] that when requesting a 'More Like this' query, no results are returned from a replica shard.

The recommendation would be to pre-cache the responses for every id - although this may be an expensive operation.

The difference in Results Between the Request Handler and the Query Parser

Using the following book details:

Title: The Black Echo
Author: Michael Connelly
Series: Harry Bosch
Genres: Mystery, Crime, Detective, Thriller
Id: 1

The Query Parser response - using q={!mlt qf=title,author,series,genre mintf=0 mindf=0 minwl=0}1

Returns the following book titles.

  • Michael Connelly - The Last Coyote
  • Michael Connelly - City of Bones
  • Michael Connelly - The Black Ice
  • Michael Connelly - The Concrete Blond
  • Michael Connelly - Trunk Music

Whilst the Request Handler response - with the same URL parameters encoded - using mlt.fl=title,author,series,genre&mlt.mintf=0&mlt.mindf=0&q=id:1&mlt.minwl=0 returns a wider range of titles.

  • Michael Connelly - The Last Coyote
  • Michael Connelly - City of Bones
  • Andy Weir - Artemis
  • Andy Weir - Project Hail Mary
  • Mary Wollstonecraft Shelley - Frankenstein

For the request handler example above, the interestingTerms configuration was set to 'details' and boost was set to true which also returned an Interesting Terms JSON Object in the response which gives an insight into how each of the titles were chosen.

Interesting Terms (with the boost value in brackets)

  • genre:Crime (1.7234258651733398)
  • genre:Detective (1.245267391204834)
  • genre:Mystery (1.150124430656433)
  • genre:Thriller (1)
  • author:Michael Connelly (1.36171293258667)
  • title:the (1)
  • title:black (1.7234258651733398)
  • title:echo (1.7234258651733398)
  • series:Harry Bosch (1)

Why were they chosen:

Author / Title

Genre:

Crime,

Detective,

Mystery,

Thriller

Author:

Michael Connelly

Title:

The,

Black,

Echo

Series:

Harry Bosch

Michael Connelly /
The Last Coyote

Match on

Crime,

Detective,

Mystery,

Thriller

Match

Match on

'
The'

Match

Michael Connelly /
City of Bones

Match on

Crime,

Detective,

Mystery,

Thriller

Match

Match

Andy Weir /
Artemis

Match on

Crime,

Thriller

Andy Weir /
Project Hail Mary

Match on

Mystery,

Thriller

Mary Wollstonecraft Shelley /
Frankenstein

Match on

Mystery,

Thriller

The More Like This  Request Handler

To configure the Request Handler in the Panl server, use the following properties

01

02

03

04

05

06

07

08

09

10

11

panl.mlt.enable=true

panl.mlt.handler=/mlt

panl.mlt.type=mlt

panl.mlt.numretries=6

panl.mlt.fl=title,author,series,genre

panl.mlt.mintf=0

panl.mlt.mindf=0

panl.mlt.minwl=0

panl.mlt.boost=true

panl.mlt.interestingTerms=details

panl.mlt.match.include=true

IMPORTANT: For any field that you wish to use for the 'More Like This' functionality, the underlying analysed Solr field MUST  have the attribute termVectors="true" for the field configuration.

When you are comfortable with the results that are being returned, you may then

panl.mlt.interestingTerms=none

panl.mlt.match.include=false

Or just not set the properties at all.

The More Like This Query Parser

01

02

03

04

05

06

07

08

panl.mlt.enable=true

panl.mlt.handler=/select

panl.mlt.type=select

panl.mlt.mintf=0

panl.mlt.mindf=0

panl.mlt.minwl=0

panl.mlt.boost=true

panl.mlt.qf=title,author,series,genre

To get better results, use the panl.mlt.qf property to base the query on specific fields to get a wider range of results

~ ~ ~ * ~ ~ ~