-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathpage-templates.html
383 lines (353 loc) · 15.5 KB
/
page-templates.html
1
2
3
4
5
6
7
8
9
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
---
# Copyright Vespa.ai. All rights reserved.
title: "Page Templates"
---
<p>
When multiple kinds of data is fetched for a request, the application
must decide how to lay out the data to return to the user.
<em>Page templates</em> allows such page layouts to be defined as XML
configuration files - one file per layout, corresponding to one use case.
</p><p>
The layouts are <em>structural</em> - they do not specify widths
and heights, colors and similar, but define the various boxed
components that will make up the page, and their ordering and nesting.
It is also assumed that the complete application includes a <em>frontend</em>
which is capable of rendering finished pages from result laid out by a template.
</p><p>
Page layouts may contain <em>choices</em> which specify alternative
versions of the template. The choices in a template are taken by
a <em>resolver</em> component at run time. Given an optimizing
resolver the system can then learn to make the right choices given
each particular query and result. An optimizing resolver is not
bundled with the platform but must be added as a component.
</p><p>
This document describes how to get started,
explains the <a href="#introduction">page template language</a>
and <a href="#using-choice-resolvers">how to add a choice resolver</a>.
A complete reference of all the permissible content of page templates is found in the
<a href="reference/page-templates-syntax.html">page template reference</a>.
</p>
<h2 id="getting-started">Getting Started</h2>
<p>
A page template is an XML file which is placed in the
directory <code>search/page-templates/</code> in
the <a href="application-packages.html">application package</a>.
To start using page templates:
</p>
<ul>
<li>Create template XML files as
shown <a href="#introduction">below</a>
in <code>[app-package]/page-templates/</code></li>
<li>Add the searcher
<a href="https://javadoc.io/doc/com.yahoo.vespa/container-search/latest/com/yahoo/search/pagetemplates/PageTemplateSearcher.html">com.yahoo.search.pagetemplates.PageTemplateSearcher</a>
to the default <a href="reference/services-search.html">search chain</a> in <em>services.xml</em>.</li>
<li><a href="application-packages.html#deploy">deploy</a>
the application package.</li>
<li>Add these query parameters: <code>page.id=[comma-separated list of page id's]</code>
and <code>presentation.format=<a href="reference/page-result-format.html">page</a></code>.</li>
</ul>
<p>
The results returned will be as defined by the page template selected for each query.
</p><p>
The source names used in page templates are the same as those defined
in the <a href="federation.html">federation</a> setup,
and/or of any internal search clusters defined in the application.
</p><p>
A presentation layer (frontend) which understands the results created
by the page templates in use must be set up or created to produce rendered pages.
That is beyond the scope of this document.
</p>
<h2 id="introduction">Introduction to Page Templates</h2>
<p>
A page template is an XML file which contains
a <code><page></code> tag at the top level. The page element
must have an <code>id</code> attribute, where the file name is the
same as the id, followed by <em>.xml</em>. If the id
is <em>default</em>, this template will be used whenever no template
is specified in the query. The templates may also be versioned,
see <a href="reference/component-reference.html#component-versioning">Component Versioning</a>.
</p><p>
A page template consist of nested <em>sections</em> which correspond
to screen areas in the final layout. The top level section is defined
by the page itself, while further sections can be defined by explicit
<section> tags. Each section may set a layout which will be
used by the frontend renderer to lay out its content
- <code>column</code> and <code>row</code> must be supported by
all renderers, while some renderers may specify additional layouts.
Each section may also specify sources of data which should be placed
in the section. Renderers must be able to render multiple data items
from different sources in a section.
</p><p>
For example, this template creates a page consisting of four equally large regions containing one source each:
</p>
<pre>
<page id="fourSquare" layout="column">
<section layout="row">
<section source="news"/>
<section source="web"/>
</section>
<section layout="row">
<section source="image"/>
<section source="video"/>
</section>
</page>
</pre>
<p>
To use this template, save it as <em>[application-package]/page-templates/fourSquare.xml</em>.
</p><p>
Suppose we want to extend this template to be able to also show blogs in the "news" section.
This can be done as follows:
</p>
<pre>
<page id="fourSquare" layout="column">
<section layout="row">
<section source="news <strong>blog</strong>"/>
<section source="web"/>
</section>
<section layout="row">
<section source="image"/>
<section source="video"/>
</section>
</page>
</pre>
<p>
Data items from each possible source has a rendering implemented by the frontend.
These renderers are used when nothing is specified in the template.
If some alternative rendering is desired, this can be
specified by a <code>renderer</code> tag. The same is true for
rendering of the sections themselves. Here we specify a different
renderer for blog data items (hits), as well as for the entire
<em>news/blog</em> section.
</p>
<pre>
<page id="fourSquare" layout="column">
<section layout="row">
<section source="news">
<strong><renderer name="blueSection">
<source name="blog">
<renderer name="newBlogHitStyle"/>
</source>
<section/></strong>
<section source="web"/>
</section>
<section layout="row">
<section source="image"/>
<section source="video"/>
</section>
</page>
</pre>
<p>
Note that in order to add a renderer subelement, we now specify the
blog source by a tag rather than by an attribute. These two forms are
equivalent - the attribute variant is just a shorthand syntax.
</p><p>
Sources and renderers can be given arbitrary key-value parameters
- see the <a href="reference/page-templates-syntax.html">reference</a> for details.
</p><p>
But what if we want to choose either news or blogs, but not both?
This can be achieved using a choice:
</p>
<pre>
<page id="fourSquare" layout="column">
<section layout="row"> <section;>
<renderer name="blueSection">
<strong><choice>
<source name="news"/></strong>
<source name="blog">
<renderer name="newBlogHitStyle"/>
</source>
<strong></choice></strong>
<section/>
<section source="web"/>
</section>
<section layout="row">
<section source="image"/>
<section source="video"/>
</section>
</page>
</pre>
<p>
We can insert choices anywhere in a template, for example choose to
show either the first or the second row rather than both:
</p>
<pre>
<page id="fourSquare" layout="column">
<strong><choice></strong>
<section layout="row">
<section;>
<renderer name="blueSection">
<choice>
<source name="news"/>
<source name="blog">
<renderer name="newBlogHitStyle"/>
</source>
</choice>
<section/>
<section source="web"/>
</section>
<section layout="row">
<section source="image"/>
<section source="video"/>
</section>
<strong></choice></strong>
</page>
</pre>
<p>
If we wanted to choose between two groups of multiple sections (or sources),
this can be done by adding an enclosing <code>alternative</code> tag around each group.
For the common special case of assigning a set of elements to a set of placeholders,
a choice can contain a <code>map</code> tag instead of a list of alternatives.
See the <a href="reference/page-templates-syntax.html">reference</a> for details.
</p>
<h2 id="using-choice-resolvers">Using Choice Resolvers</h2>
<p>
If templates including choices are used, some component must resolve
those choices given each query and result. The system includes some
resolvers for demo and testing purposes, but a proper optimizing
resolver must be deployed as part of the application.
This section describes how to create, deploy and choose a resolver to use at runtime.
</p>
<h3 id="writing-a-resolver">Writing a Resolver</h3>
<p>
Resolvers are subclasses of
<a href="https://javadoc.io/doc/com.yahoo.vespa/container-search/latest/com/yahoo/search/pagetemplates/engine/Resolver.html">
com.yahoo.search.pagetemplates.engine.Resolver</a>.
This API defines a method which accepts the page template in use
(which contains the choices), the Query/Result pair and returns a Resolution.
It is called at runtime once for every query which uses a page template.
</p><p>
There are also some helper methods which makes it simple to write
resolvers which make each choice independently. Here is an example
resolver which makes all choices by random using this helper methods:
</p>
<pre>
package com.yahoo.search.pagetemplates.engine.resolvers;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.pagetemplates.engine.*;
import com.yahoo.search.pagetemplates.model.*;
import java.util.*;
/** A resolver which makes all choices by random. */
public class RandomResolver extends Resolver {
private Random random=new Random(System.currentTimeMillis()); // Use of this is multithread safe
/** Chooses the last alternative of any choice */
@Override
public void resolve(Choice choice, Query query, Result result, Resolution resolution) {
resolution.addChoiceResolution(choice,random.nextInt(choice.alternatives().size()));
}
/** Chooses a mapping which is always by the literal order given in the source template */
@Override
public void resolve(MapChoice choice,Query query,Result result,Resolution resolution) {
Map<String, List<PageElement>> mapping=new HashMap<String, List<PageElement>>();
// Draw a random element from the value list on each iteration and assign it to a placeholder
List<String> placeholderIds=choice.placeholderIds();
List<List<PageElement>> valueList=new ArrayList<List<PageElement>>(choice.values());
for (String placeholderId : placeholderIds)
mapping.put(placeholderId,valueList.remove(random.nextInt(valueList.size())));
resolution.addMapChoiceResolution(choice,mapping);
}
}
</pre>
<h3 id="deploying-a-resolver">Deploying a Resolver</h3>
<p>
Resolvers must be packaged as <a href="https://en.wikipedia.org/wiki/Osgi#Bundles">
OSGI bundles</a> for deployment,
see <a href="jdisc/container-components.html">container components</a>.
</p><p>
The packaged component is added to the <code>components/</code>
directory of the <a href="application-packages.html">application package</a>.
</p><p>
The page template searcher must be configured with a list of the
resolvers which should be available. This is done by expanding the
page template searcher configuration with a <em>components</em> configuration:
</p>
<pre>
<searcher id="com.yahoo.search.pagetemplates.PageTemplateSearcher" bundle="the name in <artifactId> in your pom.xml" >
<config name="container.components">
<component index="0">
<id>default</id>
<classId>com.yahoo.my.Resolver1</classId>
<bundle>myBundleSymbolicName</bundle>
</component>
<component index="1">
<id>mySecondResolver</id>
<classId>com.yahoo.my.Resolver2</classId>
<bundle>myBundleSymbolicName</bundle>
</component>
</config>
</searcher>
</pre>
<p>
With this, the application is
<a href="application-packages.html#deploy">deployed</a> as usual.
</p>
<h3 id="choosing-a-resolver">Choosing a Resolver</h3>
<p>
The resolver to use is determined by setting the query property
<code>page.resolver</code> to the id (and optionally version) of the resolver component -
either in the request, in a query profile or programmatically.
</p><p>
Two templates suitable for testing purposes are always available:
<code>native.random</code>, which makes each choice by random,
and <code>native.deterministic</code> which selects the last
alternative of each choice.
</p><p>
If the <code>page.resolver</code> parameter is not set, the resolver having the
id <code>default</code> is used. If no default resolver is deployed
the random resolver is used.
</p>
<h2 id="examples">Examples</h2>
<p>
This section contains a few complete examples of page templates.
</p><p>
A blending search result page:
</p>
<pre>
<page id="slottingSerp" layout="mainAndRight">
<section layout="column" region="main" source="*"/>
<section layout="column" region="right" source="ads"/>
</page>
</pre>
<p>A richer search result page:</p>
<pre>
<page id="richSerp" layout="mainAndRight">
<section layout="row" placement="main">
<section layout="column" description="left main pane">
<section layout="row" max="5" description="Bar of images, from one of two possible sources">
<choice>
<source name="images"/>
<source name="flickr"/>
</choice>
</section>
<section max="1" source="local map video ticker weather"
description="A single relevant graphically rich element"/>
<section max="10" source="web news"
description="Various kinds of traditional search results"/>
</section>
<section layout="column" order="[source]" source="answers blogs twitter"
description="right main pane, ugc stuff, grouped by source"/>
</section>
<section layout="column" source="ads" region="right"/>
</page>
</pre>
<p>A mapping of multiple source modules to places on the page:</p>
<pre>
<page id="MapSourcesToSections" layout="column" description="4 sources are assigned to a section each">
<section layout="row" description="row 1">
<section id="box1"><placeholder id="box1source"/></section>
<section id="box2"><placeholder id="box2source"/></section>
</section>
<section layout="row" description="row 2">
<section id="box3"><placeholder id="box3source"/></section>
<section id="box4"><placeholder id="box4source"/></section>
</section>
<choice method="myMethod">
<map to="box1source box2source box3source box4source">
<source name="source1"/>
<source name="source2"/>
<source name="source3"/>
<source name="source4"/>
</map>
</choice>
</page>
</pre>