The default ordering of a result set is left up to the server, which inside Zebra means sorting in ascending document ID order. This is not always the order humans want to browse the sometimes quite large hit sets. Ranking and sorting comes to the rescue.
 
    In cases where a good presentation ordering can be computed at
    indexing time, we can use a fixed static ranking
    scheme, which is provided for the alvis
    indexing filter. This defines a fixed ordering of hit lists,
    independently of the query issued. 
   
    There are cases, however, where relevance of hit set documents is
    highly dependent on the query processed.
    Simply put, dynamic relevance ranking 
    sorts a set of retrieved records such that those most likely to be
    relevant to your request are retrieved first. 
    Internally, Zebra retrieves all documents that satisfy your
    query, and re-orders the hit list to arrange them based on
    a measurement of similarity between your query and the content of
    each record. 
   
    Finally, there are situations where hit sets of documents should be
    sorted during query time according to the
    lexicographical ordering of certain sort indexes created at
    indexing time.
   
    Zebra uses internally inverted indexes to look up term frequencies
    in documents. Multiple queries from different indexes can be
    combined by the binary boolean operations AND, 
    OR and/or NOT (which
    is in fact a binary AND NOT operation). 
    To ensure fast query execution
    speed, all indexes have to be sorted in the same order.
   
    The indexes are normally sorted according to document 
    ID in
    ascending order, and any query which does not invoke a special
    re-ranking function will therefore retrieve the result set in
    document 
    ID
    order.
   
If one defines the
    staticrank: 1 
     
    directive in the main core Zebra configuration file, the internal document
    keys used for ordering are augmented by a preceding integer, which
    contains the static rank of a given document, and the index lists
    are ordered 
    first by ascending static rank,
    then by ascending document ID.
    Zero
    is the ``best'' rank, as it occurs at the
    beginning of the list; higher numbers represent worse scores.
   
    The experimental alvis filter provides a
    directive to fetch static rank information out of the indexed XML
    records, thus making all hit sets ordered
    after ascending static
    rank, and for those doc's which have the same static rank, ordered
    after ascending doc ID.
    See Chapter 8, ALVIS XML Record Model and Filter Module for the gory details.
   
In order to fiddle with the static rank order, it is necessary to invoke additional re-ranking/re-ordering using dynamic ranking or score functions. These functions return positive integer scores, where highest score is ``best''; hit sets are sorted according to descending scores (in contrary to the index lists which are sorted according to ascending rank number and document ID).
Dynamic ranking is enabled by a directive like one of the following in the zebra configuration file (use only one of these a time!):
 
    rank: rank-1        # default TDF-IDF like
    rank: rank-static   # dummy do-nothing
    
    Dynamic ranking is done at query time rather than
    indexing time (this is why we
    call it ``dynamic ranking'' in the first place ...)
    It is invoked by adding
    the BIB-1 relation attribute with
    value ``relevance'' to the PQF query (that is,
    @attr 2=102, see also  
    
     The BIB-1 Attribute Set Semantics, also in 
      HTML). 
    To find all articles with the word Eoraptor in
    the title, and present them relevance ranked, issue the PQF query:
    
     @attr 2=102 @attr 1=4 Eoraptor
    
     The default rank-1 ranking module implements a 
     TF/IDF (Term Frequecy over Inverse Document Frequency) like
     algorithm. In contrast to the usual definition of TF/IDF
     algorithms, which only considers searching in one full-text
     index, this one works on multiple indexes at the same time.
     More precisely, 
     Zebra does boolean queries and searches in specific addressed
     indexes (there are inverted indexes pointing from terms in the
     dictionary to documents and term positions inside documents). 
     It works like this:
     
First, the boolean query is dismantled into its principal components, i.e. atomic queries where one term is looked up in one index. For example, the query
        @attr 2=102 @and @attr 1=1010 Utah @attr 1=1018 Springer
         is a boolean AND between the atomic parts
       @attr 2=102 @attr 1=1010 Utah
         and
       @attr 2=102 @attr 1=1018 Springer
         which gets processed each for itself.
Second, for each atomic query, the hit list of documents is computed.
         In this example, two hit lists for each index  
         @attr 1=1010  and  
         @attr 1=1018 are computed.
        
Third, each document in the hit list is assigned a score (_if_ ranking is enabled and requested in the query) using a TF/IDF scheme.
         In this example, both atomic parts of the query assign the magic
         @attr 2=102 relevance attribute, and are
         to be used in the relevance ranking functions. 
        
It is possible to apply dynamic ranking on only parts of the PQF query:
          @and @attr 2=102 @attr 1=1010 Utah @attr 1=1018 Springer
         searches for all documents which have the term 'Utah' on the body of text, and which have the term 'Springer' in the publisher field, and sort them in the order of the relevance ranking made on the body-of-text index only.
Fourth, the atomic hit lists are merged according to the boolean conditions to a final hit list of documents to be returned.
This step is always performed, independently of the fact that dynamic ranking is enabled or not.
Fifth, the total score of a document is computed as a linear combination of the atomic scores of the atomic hit lists
         Ranking weights may be used to pass a value to a ranking
         algorithm, using the non-standard BIB-1 attribute type 9.
         This allows one branch of a query to use one value while
         another branch uses a different one.  For example, we can search
         for utah in the 
         @attr 1=4 index with weight 30, as
         well as in the @attr 1=1010 index with weight 20:
         
         @attr 2=102 @or @attr 9=30 @attr 1=4 utah @attr 9=20 @attr 1=1010 city
         
The default weight is sqrt(1000) ~ 34 , as the Z39.50 standard prescribes that the top score is 1000 and the bottom score is 0, encoded in integers.
The ranking-weight feature is experimental. It may change in future releases of zebra.
Finally, the final hit list is re-ordered according to scores.
    The rank-1 algorithm
    does not use the static rank 
    information in the list keys, and will produce the same ordering
    with or without static ranking enabled.
    
      Dynamic ranking is not compatible
      with estimated hit sizes, as all documents in
      a hit set must be accessed to compute the correct placing in a
      ranking sorted list. Therefore the use attribute setting
      @attr 2=102 clashes with 
      @attr 9=integer. 
     
      Dynamic ranking can be enabled during sever side CQL
      query expansion by adding @attr 2=102
      chunks to the CQL config file. For example
      
       relationModifier.relevant		= 2=102
      invokes dynamic ranking each time a CQL query of the form
       Z> querytype cql
       Z> f alvis.text =/relevant house
      is issued. Dynamic ranking can also be automatically used on specific CQL indexes by (for example) setting
       index.alvis.text                        = 1=text 2=102
      which then invokes dynamic ranking each time a CQL query of the form
       Z> querytype cql
       Z> f alvis.text = house
      is issued.
     Zebra sorts efficiently using special sorting indexes
     (type=s; so each sortable index must be known
     at indexing time, specified in the configuration of record
     indexing.  For example, to enable sorting according to the BIB-1
     Date/time-added-to-db field, one could add the line
     
        xelm /*/@created               Date/time-added-to-db:s
     
     to any .abs record-indexing configuration file.
     Similarly, one could add an indexing element of the form
     
       
      <z:index name="date-modified" type="s">
       <xsl:value-of select="some/xpath"/>
      </z:index>
      
     to any alvis-filter indexing stylesheet.
     
      Indexing can be specified at searching time using a query term
      carrying the non-standard
      BIB-1 attribute-type 7.  This removes the
      need to send a Z39.50 Sort Request
      separately, and can dramatically improve latency when the client
      and server are on separate networks.
      The sorting part of the query is separate from the rest of the
      query - the actual search specification - and must be combined
      with it using OR.
     
      A sorting subquery needs two attributes: an index (such as a
      BIB-1 type-1 attribute) specifying which index to sort on, and a
      type-7 attribute whose value is be 1 for
      ascending sorting, or 2 for descending.  The
      term associated with the sorting attribute is the priority of
      the sort key, where 0 specifies the primary
      sort key, 1 the secondary sort key, and so
      on.
     
For example, a search for water, sort by title (ascending), is expressed by the PQF query
     @or @attr 1=1016 water @attr 7=1 @attr 1=4 0
     whereas a search for water, sort by title ascending, then date descending would be
     @or @or @attr 1=1016 water @attr 7=1 @attr 1=4 0 @attr 7=2 @attr 1=30 1
     
     Notice the fundamental differences between dynamic
     ranking and sorting: there can be
     only one ranking function defined and configured; but multiple
     sorting indexes can be specified dynamically at search
     time. Ranking does not need to use specific indexes, so
     dynamic ranking can be enabled and disabled without
     re-indexing; whereas, sorting indexes need to be
     defined before indexing.