ZEBRASRV(8)

πŸ’– ZEBRASRV(8) πŸ’–

the Zebra Server manual β€” part 1 of 3, bestie πŸ’…

okay so listen. you're reading the manual page for zebrasrv, section 8 of the Commands manual. and yes i'm gonna make it cute but every single fact is staying, periodt. let's go πŸ¦‹


✨ NAME ✨

zebrasrv β€” the Zebra Server πŸ‘‘


✨ SYNOPSIS ✨

zebrasrv [-install] [-installa] [-remove] [-a file] [-v level] [-l file]
         [-u uid] [-c config] [-f vconfig] [-C fname] [-t minutes]
         [-k kilobytes] [-d daemon] [-w dir] [-p pidfile] [-ziDST1]
         [listener-spec...]

✨ DESCRIPTION ✨

so Zebra is a high-performance, general-purpose structured text indexing and retrieval engine. it reads structured records in a whole bunch of input formats (email, XML, MARC, like the whole roster) and lets you get at them through exact boolean search expressions and relevance-ranked free-text queries. it's giving overachiever and we love that 🌸

zebrasrv is the Z39.50 and SRU frontend server for the Zebra search engine and indexer. it's literally the face of the operation πŸ’…

On Unix you can run the zebrasrv server from the command line β€” and put it in the background, main character energy 😌. It may also operate under the inet daemon. On WIN32 you can run the server as a console application or as a WIN32 Service.


✨ OPTIONS ✨

bestie heads up: the options for zebrasrv are the exact same as those for YAZ' yaz-ztest. Option -c specifies a Zebra configuration file β€” and if you omit it, zebra.cfg gets read. no cap.
  • -a file β€” specify a file for dumping PDUs (for diagnostic purposes). the special name - (a dash) sends the output to stderr.
  • -S β€” don't fork or make threads on connection requests. this is good for debugging, but not recommended for real operation: even though the server is asynchronous and non-blocking, it can be nice to keep a software malfunction (okay fine, a crash) from affecting all your current users. the catch: the server can only accept a single connection in this mode πŸ™ˆ.
  • -1 β€” like -S but after one session the server exits. this mode is for debugging only.
  • -T β€” operate the server in threaded mode. the server creates a thread for each connection instead of forking a process. only available on UNIX systems that offer POSIX threads.
  • -s β€” use the SR protocol (obsolete 🫠).
  • -z β€” use the Z39.50 protocol (this is the default). this option and -s complement each other. you can use both multiple times on the same command line, between listener-specifications (see below). that way you can set up the server to listen for connections in both protocols concurrently, on different local ports. iconic, honestly 🌈
  • -l file β€” specify an output file for the diagnostic messages. the default is to write this information to stderr.
  • -c config-file β€” read configuration information from config-file. the default configuration is ./zebra.cfg.
  • -f vconfig β€” this specifies an XML file that describes one or more YAZ frontend virtual servers. see the VIRTUAL HOSTS section for details.
  • -C fname β€” sets the SSL certificate file name for the server (PEM).
  • -v level β€” the log level. use a comma-separated list of members of the set {fatal,debug,warn,log,malloc,all,none}.
  • -u uid β€” set user ID. this sets the real UID of the server process to that of the given user. it's useful if you aren't comfortable with having the server run as root, but you need to start it as such to bind a privileged port. relatable 😭
  • -w working-directory β€” the server changes to this working directory before listening on incoming connections. this option is useful when the server is operating from the inetd daemon (see -i).
  • -p pidfile β€” specifies that the server should write its Process ID to the file given by pidfile. a typical location would be /var/run/zebrasrv.pid.
  • -i β€” use this to make the server run from the inetd server (UNIX only). make sure you use the logfile option -l in conjunction with this mode, and specify the -l option before any other options πŸ‘‘
  • -D β€” use this to make the server put itself in the background and run as a daemon. if neither -i nor -D is given, the server starts in the foreground.
  • -install β€” use this to install the server as an NT service (Windows NT/2000/XP only). control the server by going to the Services in the Control Panel.
  • -installa β€” use this to install and activate the server as an NT service (Windows NT/2000/XP only). control the server by going to the Services in the Control Panel.
  • -remove β€” use this to remove the server from the NT services (Windows NT/2000/XP only).
  • -t minutes β€” idle session timeout, in minutes. default is 60 minutes.
  • -k size β€” maximum record size / message size, in kilobytes. default is 1024 KB (1 MB).
  • -d daemon β€” set the name of the daemon to be used in the hosts access file. see hosts_access(5) and tcpd(8).

πŸŽ€ listener addresses πŸŽ€

A listener-address consists of an optional transport mode followed by a colon (:) followed by a listener address. the transport mode is either a file system socket unix, a SSL TCP/IP socket ssl, or a plain TCP/IP socket tcp (which is the default).

For TCP, an address has the form

hostname | IP-number [: portnumber]

The port number defaults to 210 (the standard Z39.50 port) for privileged users (root), and 9999 for normal users. the special hostname "@" is mapped to the address INADDR_ANY, which causes the server to listen on any local interface. so chill of it ✨

The default behavior for zebrasrv β€” if started as a non-privileged user β€” is to establish a single TCP/IP listener, for the Z39.50 protocol, on port 9999.

zebrasrv @
zebrasrv tcp:some.server.name.org:1234
zebrasrv ssl:@:3000

To start the server listening on the registered port for Z39.50, or on a filesystem socket, and to drop root privileges once the ports are bound, execute the server like this from a root shell:

zebrasrv -u daemon @
zebrasrv -u daemon tcp:@:210
zebrasrv -u daemon unix:/some/file/system/socket

Here daemon is an existing user account, and the unix socket /some/file/system/socket is readable and writable for the daemon account. slay πŸ”₯


✨ Z39.50 PROTOCOL SUPPORT AND BEHAVIOR ✨

πŸ’œ Z39.50 Initialization

During initialization, the server will negotiate to version 3 of the Z39.50 protocol, and the option bits for Search, Present, Scan, NamedResultSets, and concurrentOperations will be set, if requested by the client. The maximum PDU size is negotiated down to a maximum of 1 MB by default.

The supported query types are 1 and 101. All operators are currently supported, with the restriction that only proximity units of type "word" are supported for the proximity operator. Queries can be arbitrarily complex. Named result sets are supported, and result sets can be used as operands without limitations. Searches may span multiple databases.

The server has full support for piggy-backed retrieval (see also the following section). piggybacking? we love efficiency πŸ’…

πŸ’œ Z39.50 Present

The present facility is supported in a standard fashion. The requested record syntax is matched against the ones supported by the profile of each record retrieved. If no record syntax is given, SUTRS is the default. The requested element set name, again, is matched against any provided by the relevant record profiles.

πŸ’œ Z39.50 Scan

The attribute combinations provided with the termListAndStartPoint are processed in the same way as operands in a query (see above). Currently, only the term and the globalOccurrences are returned with the termInfo structure.

πŸ’œ Z39.50 Sort

Z39.50 specifies three different types of sort criteria. Of these, Zebra supports the attribute specification type, in which case the use attribute specifies the "Sort register". Sort registers are created for those fields that are of type "sort" in the default.idx file. The corresponding character mapping file in default.idx specifies the ordinal of each character used in the actual sort.

Z39.50 allows the client to specify sorting on one or more input result sets and one output result set. Zebra supports sorting on one result set only, which may or may not be the same as the output result set.

πŸ’œ Z39.50 Close

If a Close PDU is received, the server will respond with a Close PDU with reason=FINISHED, no matter which protocol version was negotiated during initialization. If the protocol version is 3 or more, the server will generate a Close PDU under certain circumstances, including a session timeout (60 minutes by default), and certain kinds of protocol errors. Once a Close PDU has been sent, the protocol association is considered broken, and the transport connection will be closed immediately upon receipt of further data, or following a short timeout. so like, it's over over πŸ’€

πŸ’œ Z39.50 Explain

Zebra maintains a "classic" Z39.50 Explain[1] database on the side. This database is called IR-Explain-1 and can be searched using the attribute set exp-1.

The records in the explain database are of type grs.sgml. The root element for the Explain grs.sgml records is explain, thus explain.abs is used for indexing.

Note πŸ“Œ Zebra must be able to locate explain.abs in order to index the Explain records properly. Zebra will work without it, but the information will not be searchable.

…okay that's the end of part 1 bestie, do NOT close the tab, more is coming 🫢

πŸ¦‹ THE SRU SERVER πŸ¦‹

okay so on top of Z39.50, Zebra also supports the newer, way more web-friendly IR protocol SRU[2]. ✨ SRU can be carried over SOAP, or over a REST-like protocol that uses HTTP GET or POST to request search responses. The request itself is made of parameters like query, startRecord, maximumRecords and recordSchema; the response is an XML document packing the hit-count, the result-set records, diagnostics, etc. πŸ’–

Think of SRU as lowkey a few things at once: a re-casting of Z39.50 semantics into web-friendly terms; a standardisation of the ad-hoc query parameters that search engines like Google and AltaVista used to just… make up; or as a superset of A9's OpenSearch (which, fun fact, it predates πŸ‘‘).

Zebra supports Z39.50, SRU GET, SRU POST, and SRU SOAP (SRW) β€” all on the same port, clocking what protocol each incoming request is speaking and handling it accordingly. 🧚 This is achieved through the use of Deep Magic; civilians are warned not to stand too close. πŸ’…

Running zebrasrv as an SRU Server πŸŽ€

Because Zebra supports all protocols on one port, it would seem to follow that you run the SRU server exactly the same way as the Z39.50 server, as described above. And yeah, that's true β€” but only in an uninterestingly vacuous way 😭: a Zebra server run like this will indeed recognise and accept SRU requests; but since it doesn't know how to handle the CQL queries that these protocols use, all it can do is send back failure responses. rip.

πŸ‘€ Note You can cheat β€” have SRU search Zebra with a PQF query instead of CQL, using the x-pquery parameter instead of query. This is a non-standard extension of CQL, and a very naughty thing to do πŸ™ˆ, but it does give you a way to see Zebra serving SRU "right out of the box". If you start your favourite Zebra server the usual way, on port 9999, then you can send your web browser to:
http://localhost:9999/Default?version=1.1
&operation=searchRetrieve
&x-pquery=mineral
&startRecord=1
&maximumRecords=1
That'll display the XML-formatted SRU response, including the first record in the result-set found by the query mineral. πŸ“ (For clarity, the SRU URL is shown here broken across lines β€” you gotta join the lines together to make one single-line URL for the browser to submit. πŸ’–)

In order to turn on Zebra's support for CQL queries, it's necessary to have the YAZ generic front-end (which Zebra uses) translate them into the Z39.50 Type-1 query format that gets used internally. And to do that, the generic front-end's own configuration file must be used. πŸ‘‘ See the section called "YAZ SERVER VIRTUAL HOSTS"; the salient point for SRU support is that zebrasrv must be started with the -f frontendConfigFile option rather than the -c zebraConfigFile option, and that the front-end configuration file must include both a reference to the Zebra configuration file and the CQL-to-PQF translator configuration file. ✨

A minimal front-end configuration file that does the trick would read as follows:

<yazgfs>
<server>
<config>zebra.cfg</config>
<cql2rpn>../../tab/pqf.properties</cql2rpn>
</server>
</yazgfs>

The <config> element holds the name of the Zebra configuration file that was previously specified by the -c command-line argument, and the <cql2rpn> element holds the name of the CQL properties file that specifies how the various CQL indexes, relations, etc. get translated into Type-1 queries. πŸ¦‹

A zebra server running with such a configuration can then be queried using proper, conformant SRU URLs with CQL queries:

http://localhost:9999/Default?version=1.1
&operation=searchRetrieve
&query=title=utah and description=epicent*
&startRecord=1
&maximumRecords=1

✨ SRU PROTOCOL SUPPORT AND BEHAVIOR ✨

Zebra running as an SRU server supports SRU version 1.1, including CQL version 1.1. πŸ’– In particular, it provides support for the following elements of the protocol.

πŸ”₯ SRU Search and Retrieval πŸ”₯

Zebra supports the searchRetrieve operation. slay.

One of the great strengths of SRU is that it mandates a standard query language, CQL, and that all conforming implementations can therefore be trusted to correctly interpret the same queries. So it's with some shame 😭 that we admit Zebra also supports an additional query language, our own Prefix Query Format (PQF[3]). A PQF query is submitted by using the extension parameter x-pquery, in which case the query parameter must be omitted β€” which makes the request not valid SRU. πŸ™ˆ Please feel free to use this facility inside your own applications; but be aware it is not only non-standard SRU but not even syntactically valid, since it omits the mandatory query parameter. periodt.

πŸŽ€ SRU Scan πŸŽ€

Zebra supports the scan operation. Scanning using CQL syntax is the default, where the standard scanClause parameter is used. πŸ’…

On top of that, a mutant form of SRU scan is supported, using the non-standard x-pScanClause parameter in place of the standard scanClause to scan on a PQF query clause. 🧚

🌸 SRU Explain 🌸

Zebra supports explain. πŸ‘‘

The ZeeRex record explaining a database may be requested either with a fully fledged SRU request (with operation=explain and version-number specified) or with a simple HTTP GET at the server's basename. The ZeeRex record you get back in response is the one embedded in the YAZ Frontend Server configuration file that is described in the section called "YAZ SERVER VIRTUAL HOSTS". πŸ¦‹

Unfortunately 😭, the data found in the CQL-to-PQF text file must be added by hand-craft into the explain section of the YAZ Frontend Server configuration file to be able to provide a suitable explain record. Too bad, but this is all extreme new alpha stuff, and a lot of work has yet to be done ..

There is no linkage whatsoever between the Z39.50 explain model and the SRU explain response (well, at least not implemented in Zebra, that is ..). Zebra does not provide a means using Z39.50 to obtain the ZeeRex record. no cap.

πŸ’œ Other SRU operations πŸ’œ

In the Z39.50 protocol, Initialization, Present, Sort and Close are separate operations. In SRU, however, these operations do not exist. not even a little bit.

  • SRU has no explicit initialization handshake phase, but commences immediately with searching, scanning and explain operations. ✨
  • Neither does SRU have a close operation, since the protocol is stateless and each request is self-contained. (It is true that multiple SRU request/response pairs may be implemented as multiple HTTP request/response pairs over a single persistent TCP/IP connection; but the closure of that connection is not a protocol-level operation. πŸ’…)
  • Retrieval in SRU is part of the searchRetrieve operation, in which a search is submitted and the response includes a subset of the records in the result set. There is no direct analogue of Z39.50's Present operation which requests records from an established result set. In SRU, this is achieved by sending a subsequent searchRetrieve request with the query cql.resultSetId=id, where id is the identifier of the previously generated result-set. 🌈
  • Sorting in CQL is done within the searchRetrieve operation β€” in v1.1, by an explicit sort parameter, but the forthcoming v1.2 or v2.0 will most likely use an extension of the query language, CQL sorting[4]. πŸ‘‘

It can be seen, then, that while Zebra operating as an SRU server does not provide the same set of operations as when operating as a Z39.50 server, it does provide equivalent functionality. πŸ’–


πŸ“ SRU EXAMPLES πŸ“

Surf into http://localhost:9999 to get an explain response, or use

http://localhost:9999/?version=1.1&operation=explain

See number of hits for a query

http://localhost:9999/?version=1.1&operation=searchRetrieve
&query=text=(plant%20and%20soil)

Fetch record 5-7 in Dublin Core format

http://localhost:9999/?version=1.1&operation=searchRetrieve
&query=text=(plant%20and%20soil)
&startRecord=5&maximumRecords=2&recordSchema=dc

Even search using PQF queries using the extended naughty parameter x-pquery 😈

http://localhost:9999/?version=1.1&operation=searchRetrieve
&x-pquery=@attr%201=text%20@and%20plant%20soil

Or scan indexes using the extended extremely naughty parameter x-pScanClause

http://localhost:9999/?version=1.1&operation=scan
&x-pScanClause=@attr%201=text%20something

Don't do this in production code! 🚨 But it's a great fast debugging aid. πŸ”₯

πŸ¦‹ YAZ SERVER VIRTUAL HOSTS πŸ¦‹

okay bestie, this is the part where one tiny YAZ frontend server becomes many servers, and honestly? it's giving multitasking queen πŸ’…

The Virtual hosts mechanism lets a YAZ frontend server support multiple backends. Which backend gets picked depends on the TCP/IP binding (that's port + listening address) and/or the virtual host.

A backend can also be told to run out of a specific working directory. And plot twist: the YAZ frontend may do CQL[5] ➑️ RPN conversion, which means old-school traditional Z39.50 backends can be served up as an SRU[2] service. SRU Explain info for a particular backend can be specified too. so much range, fr fr ✨

For the HTTP protocol, the virtual host shows up in the Host header. For the Z39.50 protocol, the virtual host is given as it is in the Initialize Request in the OtherInfo, OID 1.2.840.10003.10.1000.81.1.

Note πŸ“Œ Not all Z39.50 clients allow the VHOST information to be set. For those clients, the selection of the backend has to rely on the TCP/IP information alone β€” port and address. no vhost, no vibes, just numbers 😭

The YAZ frontend server uses XML to describe the backend configurations. Command-line option -f specifies the filename of that XML configuration.

The config's root element is yazgfs. That element holds a list of listen elements, and then one or more server elements after them.


🎧 listen

A listen describes a listener (a transport end point) β€” like a TCP/IP one, a Unix file socket, or an SSL server. Here's what a listener can contain:

  • CDATA (required) β€” the CDATA for the listen element holds the listener string, like tcp:@:210, tcp:server1:2100, etc.
  • attribute id (optional) β€” an identifier for this listener. server sections may refer to it.
Note πŸ‘€ We expect more information to be added for the listen section in a future version, such as CERT file for SSL servers.

πŸ–₯️ server

A server describes a server and the parameters for that server type. What a server can contain:

  • attribute id (optional) β€” identifier for this server. Currently not used for anything, but it might be, for logging purposes.
  • attribute listenref (optional) β€” specifies the listener for this server. If this attribute isn't given, the server is accessible from all listener. For the server to actually get used in real life, though, the virtual host must match (if it's specified in the configuration).
  • element config (optional) β€” specifies the server configuration. This is equivalent to the config you'd give with command-line option -c.
  • element directory (optional) β€” specifies a working directory for this backend server. If it's given, the YAZ frontend changes current working directory to this directory whenever a backend of this type is started (backend handler bend_start), stopped (backend handler hand_stop) and initialized (bend_init).
  • element host (optional) β€” specifies the virtual host for this server. If this is specified, a client must specify this host string in order to use this backend.
  • element cql2rpn (optional) β€” specifies a filename that includes CQL[5] to RPN conversion for this backend server. Peep the CQL[5] section in the YAZ manual. If given, the backend server will only "see" a Type-1/RPN query.
  • element explain (optional) β€” specifies SRU[2] ZeeRex content for this server β€” copied verbatim to the client. The way things are right now, some of the Explain content seems redundant because host information, etc. is also stored elsewhere. The format of the Explain record is described in detail, with examples, on the file at the ZeeRex[6] web-site.

🌈 the example, served fresh

This XML below sets up a server that accepts connections from two ports: TCP/IP port 9900, and a local UNIX file socket. We're naming the TCP/IP server public and the other one internal.

<yazgfs>
 <listen id="public">tcp:@:9900</listen>
 <listen id="internal">unix:/var/tmp/socket</listen>
 <server id="server1">
   <host>server1.mydomain</host>
   <directory>/var/www/s1</directory>
   <config>config.cfg</config>
 </server>
 <server id="server2">
   <host>server2.mydomain</host>
   <directory>/var/www/s2</directory>
   <config>config.cfg</config>
   <cql2rpn>../etc/pqf.properties</cql2rpn>
   <explain xmlns="http://explain.z3950.org/dtd/2.0/">
     <serverInfo>
       <host>server2.mydomain</host>
       <port>9900</port>
       <database>a</database>
     </serverInfo>
   </explain>
 </server>
 <server id="server3" listenref="internal">
   <directory>/var/www/s3</directory>
   <config>config.cfg</config>
 </server>
</yazgfs>

okay so that's three configured backend servers. The first two, "server1" and "server2", can be reached by both listener addresses β€” because no listenref attribute is specified on them. To tell the two apart, a virtual host has been specified for each server in the host elements. iconic behavior πŸŽ€

For "server2", the elements for CQL[5] to RPN conversion are supported and explain information has been added (a short one, to keep the example small β€” we're not writing a novel here).

The third server, "server3", can only be reached via the listener "internal". exclusive πŸ’…


πŸ‘€ SEE ALSO


πŸ’– AUTHORS

Index Data


πŸ“ NOTES

  1. Z39.50 Explain β€” https://loc.gov/standards/z3950/agency/markup/07.html
  2. SRU β€” https://loc.gov/standards/sru/
  3. PQF β€” https://www.indexdata.com/yaz/doc/tools.html#PQF
  4. CQL sorting β€” https://zing.z3950.org/cql/sorting.html
  5. CQL β€” https://loc.gov/standards/sru/cql/
  6. ZeeRex β€” https://zeerex.z3950.org/

and that's a wrap bestie 🫢 this whole page is zebra 2.2.11, dated 05/27/2026, and lives in section ZEBRASRV(8) of the manual. go configure some virtual hosts, you absolute main character βœ¨πŸ‘‘

πŸ“¦ where this page comes from