opencms days 2015 advanced solr searching

Post on 19-Jan-2017

461 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Daniel Seidel – Alkacon Software GmbH

Advanced searching

29.09.2015

2

What can you expect?

Presentation of new

OpenCms features

A tutorial on advanced Solr

features

3

A short history on searching

OpenCms 6.0

● Simple server-side search

● Many uni-lingual indexes

● Many proprietary configuration options

OpenCms 8.5

● Many more features ● Facets

● Highlighting

● Did you mean?

● …

● Multilingual indexes

● Support for client-side searches ?

4

Building a search page - Lucene

How to

● Configure your index (one per language)

● Write JSP using CmsSearch as bean

Pros and Cons

Easily produce a search page Easy query options, incl. simple filter and sort options

Pagination support

Scriptlet code necessary

All server-side code

Index configuration necessary (for each language)

No support for facets etc.

5

Building a search page - Solr

How to

● Write a custom client side search (using GWT)

● Adjust the demo search (may include altering GWT code)

Pros and Cons

Great search experience possible

All Ajax based

Many great features: facets, auto-completion, “Did you mean?”

“unlimited” sorting options

Relies heavily on JavaScript

Very complex to build and adjust

State keeping

Html rendering with JavaScript

Nearly always a per-customer solution

6

Combining the Advantages

Simplicity

since 6.0

Many features

since 8.5

● Stay on the server side (JSP)

● Class like CmsSearch, but

● Expose more Solr features

● Usable without scriptlet code

Design questions 7

What is the value of CmsSearch?

Simple search API tailored for OpenCms

Managing state

Hiding search details

Mapping from request parameters to

search options

Design questions 8

What can we support for Solr?

Simple search API tailored for OpenCms

Managing state

Mapping from request parameters to

search options

Hiding all search details

Design questions 9

How can we ease usage?

Reduce configuration to a minimal

Avoid explicit bean initialization

Allow to add raw Solr query parts

Easy access to results, state, configuration

(no scriptlet code necessary)

● Via search you obtain

● Configuration

● State (current query, checked facet entries, ...)

● Results (search results, facet items, ...)

● Via configFile a special XML content is given

● You drag search form configurations on the page

to render a fully functional search form

● A “feature-complete” default formatter is provided

10

The new tag: <cms:search>

<cms:search var="search"

configFile="${content.filename}"/>

● Live Demo

Drag & Drop your search form

Demo

Demo Demo Demo

デモ

Search form creation

● Request parameters

● In cases where the default causes collisions

● In cases where additional parameters should be

handled

● General search options

● Core / Index

● Search for empty query?

● Escape query string?

● Query string modifier

● Add additional query parameters

12

What can I configure? (I)

● Special search options

● Pagination

● Sorting

● Facets (field and query facets)

● Highlighting

● Did you mean?

13

What can I configure? (II)

Important

You can, but need not necessarily

configure everything!

I_CmsSearchResultWrapper

I_CmsSearchControllerMain

Single controllers with

configuration and state

Result information

Results list

Facets result

Highlighting result

Page info

...

I_CmsSearchStateParameters

14

Structure of the result object

Configure the UI

elements

(input field names

and current

state/value)

Print results,

facet items,

etc.

Create a suitable link

that contains the

complete state of the

search form

<!-- ... -->

<c:set var="controllers" value="${search.controller}"/>

<!-- ... -->

<c:set var="sort" value="${controllers.sorting}"/>

<!-- ... -->

<select name="${sort.config.sortParam}">

<c:forEach var="option"

items="${sort.config.sortOptions}">

<option value="${option.paramValue}"

${sort.state.checkSelected[option]?"selected":""}>

${option.label}

</option>

</c:forEach>

</select>

<!-- ... -->

15

Rendering example: Sort options

<!-- ... -->

<c:set var="controllers" value="${search.controller}"/>

<!-- ... -->

<c:set var="sort" value="${controllers.sorting}"/>

<!-- ... -->

<select name="${sort.config.sortParam}">

<c:forEach var="option"

items="${sort.config.sortOptions}">

<option value="${option.paramValue}"

${sort.state.checkSelected[option]?"selected":""}>

${option.label}

</option>

</c:forEach>

</select>

<!-- ... -->

16

Rendering example: Sort options

Use abbreviations

<!-- ... -->

<c:set var="controllers" value="${search.controller}"/>

<!-- ... -->

<c:set var="sort" value="${controllers.sorting}"/>

<!-- ... -->

<select name="${sort.config.sortParam}">

<c:forEach var="option"

items="${sort.config.sortOptions}">

<option value="${option.paramValue}"

${sort.state.checkSelected[option]?"selected":""}>

${option.label}

</option>

</c:forEach>

</select>

<!-- ... -->

17

Rendering example: Sort options

Use the configuration

<!-- ... -->

<c:set var="controllers" value="${search.controller}"/>

<!-- ... -->

<c:set var="sort" value="${controllers.sorting}"/>

<!-- ... -->

<select name="${sort.config.sortParam}">

<c:forEach var="option"

items="${sort.config.sortOptions}">

<option value="${option.paramValue}"

${sort.state.checkSelected[option]?"selected":""}>

${option.label}

</option>

</c:forEach>

</select>

<!-- ... -->

18

Rendering example: Sort options

Use the state

<!-- ... -->

<c:forEach var="searchResult" items="${search.searchResults}">

<a href='<cms:link>${searchResult.fields["path"]}</cms:link>'>

${searchResult.fields["Title_prop"]}

</a>

<p>

${cms:trimToSize(

fn:escapeXml(searchResult.fields["content_en"])

,250)}

</p>

<hr />

</c:forEach>

<!-- ... -->

19

Rendering example: Results

<!-- ... -->

<c:forEach var="searchResult" items="${search.searchResults}">

<a href='<cms:link>${searchResult.fields["path"]}</cms:link>'>

${searchResult.fields["Title_prop"]}

</a>

<p>

${cms:trimToSize(

fn:escapeXml(searchResult.fields["content_en"])

,250)}

</p>

<hr />

</c:forEach>

<!-- ... -->

20

Rendering example: Results

Loop over the result collection

(get I_CmsSearchResourceBean objects)

<!-- ... -->

<c:forEach var="searchResult" items="${search.searchResults}">

<a href='<cms:link>${searchResult.fields["path"]}</cms:link>'>

${searchResult.fields["Title_prop"]}

</a>

<p>

${cms:trimToSize(

fn:escapeXml(searchResult.fields["content_en"])

,250)}

</p>

<hr />

</c:forEach>

<!-- ... -->

21

Rendering example: Results

Access index fields

<!-- ... -->

<c:set var="fControllers"

value="${controllers.fieldFacets}"/>

<c:forEach var="facet" items="${search.fieldFacets}">

<c:set var="facetController"

value="${fControllers.fieldFacetController[facet.name]}"/>

<c:if test="${cms:getListSize(facet.values) > 0}">

<!-- Render facet – see next slide -->

</c:if>

</c:forEach>

<!-- ... -->

22

Rendering example: Facets (I)

<!-- ... -->

<c:set var="fControllers"

value="${controllers.fieldFacets}"/>

<c:forEach var="facet" items="${search.fieldFacets}">

<c:set var="facetController"

value="${fControllers.fieldFacetController[facet.name]}"/>

<c:if test="${cms:getListSize(facet.values) > 0}">

<!-- Render facet – see next slide -->

</c:if>

</c:forEach>

<!-- ... -->

23

Rendering example: Facets (I)

Loop over facets from the

search result

<!-- ... -->

<c:set var="fControllers"

value="${controllers.fieldFacets}"/>

<c:forEach var="facet" items="${search.fieldFacets}">

<c:set var="facetController"

value="${fControllers.fieldFacetController[facet.name]}"/>

<c:if test="${cms:getListSize(facet.values) > 0}">

<!-- Render facet – see next slide -->

</c:if>

</c:forEach>

<!-- ... -->

24

Rendering example: Facets (I)

Get the facet’s controller

<!-- ... -->

<c:set var="fControllers"

value="${controllers.fieldFacets}"/>

<c:forEach var="facet" items="${search.fieldFacets}">

<c:set var="facetController"

value="${fControllers.fieldFacetController[facet.name]}"/>

<c:if test="${cms:getListSize(facet.values) > 0}">

<!-- Render facet – see next slide -->

</c:if>

</c:forEach>

<!-- ... -->

25

Rendering example: Facets (I)

Render the facet if necessary

(see next slide)

<!-- ... -->

<div>${facetController.config.label}</div>

<c:forEach var="facetItem" items="${facet.values}">

<div class="checkbox">

<label>

<input type="checkbox"

name="${facetController.config.paramKey}"

value="${facetItem.name}"

${facetController.state.isChecked[facetItem.name]

?"checked":""} />

${facetItem.name} (${facetItem.count})

</label>

</div>

</c:forEach>

<!-- ... -->

26

Rendering example: Facets (II)

<!-- ... -->

<div>${facetController.config.label}</div>

<c:forEach var="facetItem" items="${facet.values}">

<div class="checkbox">

<label>

<input type="checkbox"

name="${facetController.config.paramKey}"

value="${facetItem.name}"

${facetController.state.isChecked[facetItem.name]

?"checked":""} />

${facetItem.name} (${facetItem.count})

</label>

</div>

</c:forEach>

<!-- ... -->

27

Rendering example: Facets (II)

Use the configuration

<!-- ... -->

<div>${facetController.config.label}</div>

<c:forEach var="facetItem" items="${facet.values}">

<div class="checkbox">

<label>

<input type="checkbox"

name="${facetController.config.paramKey}"

value="${facetItem.name}"

${facetController.state.isChecked[facetItem.name]

?"checked":""} />

${facetItem.name} (${facetItem.count})

</label>

</div>

</c:forEach>

<!-- ... -->

28

Rendering example: Facets (II)

Use the result

<!-- ... -->

<div>${facetController.config.label}</div>

<c:forEach var="facetItem" items="${facet.values}">

<div class="checkbox">

<label>

<input type="checkbox"

name="${facetController.config.paramKey}"

value="${facetItem.name}"

${facetController.state.isChecked[facetItem.name]

?"checked":""} />

${facetItem.name} (${facetItem.count})

</label>

</div>

</c:forEach>

<!-- ... -->

29

Rendering example: Facets (II)

Use the state

<c:set var="pagination" value="${controllers.pagination}"/>

<c:forEach var="i" begin="${search.pageNavFirst}"

end="${search.pageNavLast}">

<c:set var="is">${i}</c:set>

<li ${pagination.state.currentPage eq i ? "class='active'" : ""}>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[is]}

</cms:link>">${is}</a>

</li>

</c:forEach>

<li>

<c:set var="pages">${search.numPages}</c:set>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[pages]}

</cms:link>">Last</a>

</li>

30

Rendering example: Pagination

<c:set var="pagination" value="${controllers.pagination}"/>

<c:forEach var="i" begin="${search.pageNavFirst}"

end="${search.pageNavLast}">

<c:set var="is">${i}</c:set>

<li ${pagination.state.currentPage eq i ? "class='active'" : ""}>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[is]}

</cms:link>">${is}</a>

</li>

</c:forEach>

<li>

<c:set var="pages">${search.numPages}</c:set>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[pages]}

</cms:link>">Last</a>

</li>

31

Rendering example: Pagination

Use pagination support

<c:set var="pagination" value="${controllers.pagination}"/>

<c:forEach var="i" begin="${search.pageNavFirst}"

end="${search.pageNavLast}">

<c:set var="is">${i}</c:set>

<li ${pagination.state.currentPage eq i ? "class='active'" : ""}>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[is]}

</cms:link>">${is}</a>

</li>

</c:forEach>

<li>

<c:set var="pages">${search.numPages}</c:set>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[pages]}

</cms:link>">Last</a>

</li>

32

Rendering example: Pagination

Use current state

<c:set var="pagination" value="${controllers.pagination}"/>

<c:forEach var="i" begin="${search.pageNavFirst}"

end="${search.pageNavLast}">

<c:set var="is">${i}</c:set>

<li ${pagination.state.currentPage eq i ? "class='active'" : ""}>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[is]}

</cms:link>">${is}</a>

</li>

</c:forEach>

<li>

<c:set var="pages">${search.numPages}</c:set>

<a href="<cms:link>${cms.requestContext.uri}

?${search.stateParameters.setPage[pages]}

</cms:link>">Last</a>

</li>

33

Rendering example: Pagination

Use state parameters

● Two options to send the current state:

● Submit a form

● Use state parameters

● With state parameters

● Everything is manipulated explicitly

● You do not need a form at all

● With a form

● You must make sure to send all the state you want

(use hidden parameters, e.g., for the last query)

● You can intentionally prevent state transmission

(e.g., for the current page)

34

Form vs. state parameters

● We did

● Introduce the tag <cms:search>

● See its configuration via an XML content

● Explore how to write a formatter for a search form

● If you need more information on formatting

● Explore the default formatter

● Explore the classes under org.opencms.jsp.search.result

● We did not

● Cover all configuration options

● See all use cases for <cms:search>

35

Short summary

● Intention

● Show blogs, news, ...

● Link to detail pages

● Realization

● <cms:contentload>

● Manifold collectors

● Question

● Where’s the

difference between

lists and a search

result page?

36

Lists in OpenCms

● Intention

● Show blogs, news, ...

● Link to detail pages

● Realization

● <cms:contentload>

● Manifold collectors

● Question

● Where’s the

difference between

lists and a search

result page?

37

Lists in OpenCms

Essentially, there is no

difference!

38

A short history of lists

● Simple way to render lists

● Many specific collectors

● Facility to edit list entries directly

OpenCms 6.0 <cms:contentload> is introduced

OpenCms 8.5

● Collecting “byQuery” or “byContext”

● First contact of Search and Lists

● No facets etc. supported

CmsSolrCollector is added

OpenCms 10 <cms:search> and <cms:edit> are introduced

● Lists and search become one

● Facets etc. available for lists

● Editing becomes decoupled from lists ?

● What is specific for a list?

● XML content for configuration is unsuitable

● There is no query string provided by the user

● Usually there is no form

● XML contents, not the index is accessed

● How does <cms:search> handle the pecularities

● Configuration via JSON (String or file)

● An option to ignore the query parameter

● The already seen state parameters

(no form is necessary)

● I_CmsSearchResourceBean allows to access XML

contents via the CmsJspContentAccessBean

39

Lists with <cms:search>

● Live Demo

Watch out for the Solr features

Demo

Demo Demo Demo

デモ

A list with <cms:search>

<c:set var="searchConfig">

{ "ignorequery" : true,

"extrasolrparams" :

"fq=type:u-blog&fq=parent-folders:

\"/sites/default/.content/blogentries/\"",

"pagesize" : ${content.value.pageSize},

"pagenavlength" : ${cms.element.settings["navlength"]}

<!-- Facet and sort option configuration -->

}

</c:set>

<cms:search configString="${searchConfig}" var="search"/>

<!-- ... -->

41

The JSON configuration for a list

<c:set var="searchConfig">

{ "ignorequery" : true,

"extrasolrparams" :

"fq=type:u-blog&fq=parent-folders:

\"/sites/default/.content/blogentries/\"",

"pagesize" : ${content.value.pageSize},

"pagenavlength" : ${cms.element.settings["navlength"]}

<!-- Facet and sort option configuration -->

}

</c:set>

<cms:search configString="${searchConfig}" var="search"/>

<!-- ... -->

42

The JSON configuration for a list

Most important options

<c:set var="searchConfig">

{ "ignorequery" : true,

"extrasolrparams" :

"fq=type:u-blog&fq=parent-folders:

\"/sites/default/.content/blogentries/\"",

"pagesize" : ${content.value.pageSize},

"pagenavlength" : ${cms.element.settings["navlength"]}

<!-- Facet and sort option configuration -->

}

</c:set>

<cms:search configString="${searchConfig}" var="search"/>

<!-- ... -->

43

The JSON configuration for a list

Optional extra features

<c:set var="searchConfig">

{ "ignorequery" : true,

"extrasolrparams" :

"fq=type:u-blog&fq=parent-folders:

\"/sites/default/.content/blogentries/\"",

"pagesize" : ${content.value.pageSize},

"pagenavlength" : ${cms.element.settings["navlength"]}

<!-- Facet and sort option configuration -->

}

</c:set>

<cms:search configString="${searchConfig}" var="search"/>

<!-- ... -->

44

The JSON configuration for a list

The content adjusts the configuration

<c:choose>

<c:when test="${search.numFound > 0}">

<c:forEach var="result" items="${search.searchResults}">

<c:set var="content" value="${result.xmlContent}"/>

<!-- render entry as usual -->

</c:forEach>

</c:when>

<c:otherwise>

No results found.

</c:otherwise>

</c:choose>

45

Rendering the list entries

Easier than before

Getting results and iterating over

them is separated

No nested <cms:contentload>

anymore

● <cms:contentload> supported

● Editing, adding or deleting list entries

● Adding entries to an empty list

● Can we provide the same feature?

● No, because iteration is separated from <cms:search>

● Do we need the same feature?

● No, there’s no reason why edit options and content

loading has to be coupled

● Can we get similar edit options differently?

● Yes, a special <cms:edit> tag

46

Editing list entries

● Places edit points wherever you like

● Allows to edit or delete existing XML contents

● Allows to add new contents

● Highlights the enclosed HTML when hovering

over the edit point

● New contents can be placed

● At the place configured in the sitemap configuration

● In a provided folder

● Where the content that is edited is located

47

The tag <cms:edit>

<c:choose>

<c:when test="${search.numFound > 0}">

<c:forEach var="result" items="${search.searchResults}">

<c:set var="content" value="${result.xmlContent}"/>

<cms:edit uuid='${result.fields["id"]}'

create="true" delete="true">

<!-- render entry as usual -->

</cms:edit>

</c:forEach>

</c:when>

<c:otherwise>

<cms:edit createType="u-blog">

<div>No results found.</div>

</cms:edit>

</c:otherwise>

</c:choose>

48

Edit options for the list

Easier than before

Harmonized usage for empty

and non-empty list

● How about the “Publish this page” option?

● <cms:contentload> with attribute “editable” causes list entries to be related to the page

● Do we have a similar mechanism?

● Using <cms:edit> the edited content becomes related to the page

● But does this suffice?

● Not if we use pagination.

● So can we do better?

● Yes: <cms:search ... addContentInfo="true">

● All list entries become related to the page

49

Do we still miss a feature?

50

What should you remember?

Server-sided Solr search becomes easy

Search pages and lists become the same

Edit point needed: Use <cms:edit>

By, by <cms:contentload> and friends

● Containers in lists

● Container tag takes the element(s)

<cms:container ... elements="${uuid}"/>

● Rendering is done by a suitable formatter

51

What’s next? (Maybe)

Easily render contents of different types

Inline editing will work out of the box

Harmonized rendering of XML contents

● Containers in lists

● Container tag takes the element(s)

<cms:container ... elements="${uuid}"/>

● Rendering is done by a suitable formatter

52

What’s next? (Maybe)

Easily render contents of different types

Inline editing will work out of the box

Harmonized rendering of XML contents

53

Last comments

Solr updated to version 5.1

(further updates follow)

Gallery index replaced by “Solr offline”

(watch out for bugs)

This is OpenCms 10 Alpha 1

(don’t expect everything in the final state)

Daniel Seidel

Alkacon Software GmbH

http://www.alkacon.com

http://www.opencms.org

Thank you very much for your attention!

top related