From 09c6a88923a35a412d1ebabeb0e1f80070820030 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Lahmann?= <lahmann@ub.uni-leipzig.de>
Date: Wed, 24 Feb 2016 18:59:56 +0100
Subject: [PATCH] refs #5076: * added searchspecs.yaml to alpha and dev
 (sample) * updated searchspecs.yaml, SolrDefault and SolrDefaultFincTrait to
 use dynamic callnumber Solr fields * marked methods in SolrMarcFincTrait
 using Solr itemData field as deprecated

---
 local/alpha/config/vufind/searchspecs.yaml    | 739 ++++++++++++++++++
 local/config/vufind/searchspecs.yaml          |  80 +-
 .../dev/config/vufind/searchspecs.yaml.sample | 739 ++++++++++++++++++
 .../src/finc/RecordDriver/SolrDefault.php     |  29 +
 .../RecordDriver/SolrDefaultFincTrait.php     |  12 +
 .../finc/RecordDriver/SolrMarcFincTrait.php   |   2 +
 6 files changed, 1566 insertions(+), 35 deletions(-)
 create mode 100644 local/alpha/config/vufind/searchspecs.yaml
 create mode 100644 local/dev/config/vufind/searchspecs.yaml.sample

diff --git a/local/alpha/config/vufind/searchspecs.yaml b/local/alpha/config/vufind/searchspecs.yaml
new file mode 100644
index 00000000000..498d584b19e
--- /dev/null
+++ b/local/alpha/config/vufind/searchspecs.yaml
@@ -0,0 +1,739 @@
+---
+# Listing of search types and their component parts and weights.
+#
+# Format is:
+#  searchType:
+#    # CustomMunge is an optional section to define custom pre-processing of
+#    #     user input.  See below for details of munge actions.
+#    CustomMunge:
+#      MungeName1:
+#        - [action1, actionParams]
+#        - [action2, actionParams]
+#        - [action3, actionParams]
+#      MungeName2:
+#        - [action1, actionParams]
+#    # DismaxFields is optional and defines the fields sent to the Dismax handler
+#    #     when we are able to use it.  QueryFields will be used for advanced
+#    #     searches that Dismax cannot support.  QueryFields is always used if no
+#    #     DismaxFields section is defined.
+#    DismaxFields:
+#      - field1^boost
+#      - field2^boost
+#      - field3^boost
+#    # DismaxParams is optional and allows you to override default Dismax settings
+#    #     (i.e. mm / bf) on a search-by-search basis. Enclose the parameter values
+#    #     in quotes for proper behavior. If you want global default values for these
+#    #     settings, you can edit the appropriate search handler in
+#    #     solr/biblio/conf/solrconfig.xml.
+#    DismaxParams:
+#      - [param1_name, param1_value]
+#      - [param2_name, param2_value]
+#      - [param3_name, param3_value]
+#    # This optional setting may be used to specify which Dismax handler to use. By
+#    #     default, VuFind provides two options: dismax (for the old, standard
+#    #     Dismax) and edismax (for Extended Dismax). You can also configure your own
+#    #     in solrconfig.xml, but VuFind relies on the name "edismax" to identify an
+#    #     Extended Dismax handler. If you omit this setting, the default value from
+#    #     the default_dismax_handler setting in the [Index] section of config.ini
+#    #     will be used.
+#    DismaxHandler: dismax|edismax
+#    # QueryFields define the fields we are searching when not using Dismax; VuFind
+#    #     detects queries that will not work with Dismax and switches to QueryFields
+#    #     as needed.
+#    QueryFields:
+#      SolrField:
+#        - [howToMungeSearchstring, weight]
+#        - [differentMunge, weight]
+#      DifferentSolrField:
+#        - [howToMunge, weight]
+#    # The optional FilterQuery section allows you to AND a static query to the
+#    #     dynamic query generated using the QueryFields; see JournalTitle below
+#    #     for an example.  This is applied whether we use DismaxFields or
+#    #     QueryFields.
+#    FilterQuery: (optional Lucene filter query)
+#    ExactSettings:
+#      DismaxFields: ...
+#      QueryFields: ...
+#    # All the same settings as above, but for exact searches, i.e. search terms
+#    #     enclosed in quotes. Allows different fields or weights for exact
+#    #     searches. See below for commented-out examples.
+#
+# ...etc.
+#
+#-----------------------------------------------------------------------------------
+#
+# Within the QueryFields area, fields are OR'd together, unless they're in an
+# anonymous array with a numeric instead of alphanumeric key, in which case the
+# first element is a two-value array that tells us what the type (AND or OR) and
+# weight of the whole group should be.
+#
+# So, given:
+#
+# test:
+#   QueryFields:
+#     A:
+#       - [onephrase, 500]
+#       - [and, 200]
+#     B:
+#       - [and, 100]
+#       - [or, 50]
+#     # Start an anonymous array to group; first element indicates AND grouping
+#     #     and a weight of 50
+#     0:
+#       0:
+#         - AND
+#         - 50
+#       C:
+#         - [onephrase, 200]
+#       D:
+#         - [onephrase, 300]
+#       # Note the "not" attached to the field name as a minus, and the use of ~
+#       #     to mean null ("no special weight")
+#       -E:
+#         - [or, ~]
+#     D:
+#       - [or, 100]
+#
+#  ...and the search string
+#
+#      test "one two"
+#
+#  ...we'd get
+#
+#   (A:"test one two"^500 OR
+#    A:(test AND "one two")^ 200 OR
+#    B:(test AND "one two")^100 OR
+#    B:(test OR "one two")^50
+#    (
+#      C:("test one two")^200 AND
+#      D:"test one two"^300 AND
+#      -E:(test OR "one two")
+#    )^50 OR
+#    D:(test OR "one two")^100
+#   )
+#
+#-----------------------------------------------------------------------------------
+#
+# Munge types are based on the original Solr.php code, and consist of:
+#
+# onephrase: eliminate all quotes and do it as a single phrase. 
+#   testing "one two"
+#    ...becomes ("testing one two")
+#
+# and: AND the terms together
+#  testing "one two"
+#   ...becomes (testing AND "one two")
+#
+# or: OR the terms together
+#  testing "one two"
+#   ...becomes (testing OR "one two")
+#
+# identity: Use the search as-is
+#  testing "one two"
+#   ...becomes (testing "one two")
+#
+# Additional Munge types can be defined in the CustomMunge section.  Each array
+# entry under CustomMunge defines a new named munge type.  Each array entry under
+# the name of the munge type specifies a string manipulation operation.  Operations
+# will be applied in the order listed, and different operations take different
+# numbers of parameters.
+#
+# Munge operations:
+#
+# [append, text] - Append text to the end of the user's search string
+# [lowercase] - Convert string to lowercase
+# [preg_replace, pattern, replacement] - Perform a regular expression replace
+#     using the preg_replace() PHP function.  If you use backreferences in your
+#     replacement phrase, be sure to escape dollar signs (i.e. \$1, not $1).
+# [uppercase] - Convert string to uppercase
+#
+# See the CallNumber search below for an example of custom munging in action.
+#-----------------------------------------------------------------------------------
+
+# These searches use Dismax when possible:
+Author:
+  DismaxParams:
+    - [bf , ord(publishDateSort)^10]
+  DismaxFields:
+    - author^400
+    - author2^300
+    - author_id^100
+    - author_ref^150
+    - author_corp^200
+    - author_corp2^200
+    - author_corp_ref^150
+    - author_orig^200
+    - author2_orig^200
+    - author_corp_orig^200
+    - author_corp2_orig^200
+  QueryFields:
+    - author:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author2:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    - author_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp2:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_id:
+      - [onephrase, 450]
+      - [and, 300]
+      - [or, 200]
+
+ISN:
+#  DismaxFields:
+#    - isbn
+#    - issn
+#    - ismn
+  QueryFields:
+    - issn:
+      - [and, 100]
+      - [or, ~]
+    - isbn:
+      - [and, 100]
+      - [or, ~]
+    - ismn:
+      - [and, 100]
+      - [or, ~]
+
+Signatur:
+  DismaxParams:
+    - [mm, 0]
+  DismaxFields:
+    - callnumber_ISIL
+  QueryFields:
+    - callnumber_ISIL:
+      - [or, ~]
+  #    - [and, 100]
+  #    - [or, ~]
+
+Barcode:
+  DismaxParams:
+    - [mm, 0]
+  DismaxFields:
+    - barcode_ISIL
+  QueryFields:
+    - barcode_ISIL:
+      #- [and, 100]
+      - [or, ~]
+
+Subject:
+  DismaxFields:
+    - topic_unstemmed^150
+    - topic^100
+    - topic_id^100
+    - topic_ref^100
+    #- geographic^50
+    #- genre^50
+    #- era
+  QueryFields:
+    - topic_unstemmed:
+      - [onephrase, 350]
+      - [and, 150]
+      - [or, ~]
+    - topic:
+      - [onephrase, 300]
+      - [and, 100]
+      - [or, ~]
+    - topic_ref:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    - topic_id:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    #- geographic:
+    #  - [onephrase, 300]
+    #  - [and, 100]
+    #  - [or, ~]
+    #- genre:
+    #  - [onephrase, 300]
+    #  - [and, 100]
+    #  - [or, ~]
+    #- era:
+    #  - [and, 100]
+    #  - [or, ~]
+#  ExactSettings:
+#    DismaxFields:
+#      - topic_unstemmed^150
+#    QueryFields:
+#      - topic_unstemmed:
+#        - [onephrase, 350]
+#        - [and, 150]
+#        - [or, ~]
+
+# This field definition is a compromise that supports both journal-level and
+# article-level data.  The disadvantage is that hits in article titles will
+# be mixed in.  If you are building a purely article-oriented index, you should
+# customize this to remove all of the title_* fields and focus entirely on the
+# container_title field.
+JournalTitle:
+  DismaxFields:
+    - title_short^500
+    - title_full_unstemmed^450
+    - title_full^400
+    - title^300
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - series^100
+    - series2
+  QueryFields:
+    - title_short:
+      - [onephrase, 500]
+    - title_full_unstemmed:
+      - [onephrase, 450]
+      - [and, 400]
+    - title_full:
+      - [onephrase, 400]
+    - title:
+      - [onephrase, 300]
+      - [and, 250]
+    - title_alt:
+      - [and, 200]
+    - title_new:
+      - [and, 100]
+    - title_old:
+      - [and, ~]  
+    - series:
+      - [onephrase, 100]
+      - [and, 50]
+    - series2:
+      - [onephrase, 50]
+      - [and , ~]
+  FilterQuery: "format:Journal"
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^450
+#    QueryFields:
+#      - title_full_unstemmed:
+#        - [onephrase, 450]
+#        - [and, 400]
+#    FilterQuery: "format:Journal OR format:Article"
+
+Title:
+  DismaxParams:
+    - [mm, 3]
+    - [bf , ord(publishDateSort)^10]
+  DismaxFields:
+#    - title_sub^200
+#    - title_short^300
+    - title_full_unstemmed^150
+    - title_full^100
+    - title^900
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - title_orig^400
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    - title_short:
+      - [onephrase, 500]
+    - title_full_unstemmed:
+      - [onephrase, 150]
+      - [and, 100]
+    - title_full:
+      - [onephrase, 100]
+    - title:
+      - [onephrase, 300]
+      - [and, 250]
+    - title_alt:
+      - [and, 200]
+    - title_new:
+      - [and, 100]
+    - title_old:
+      - [and, ~]
+    - title_orig:
+      - [onephrase, 500]
+      - [and, 200]
+    - series:
+      - [onephrase, 100]
+      - [and, 50]
+    - series2:
+      - [onephrase, 50]
+      - [and , ~]
+    - series_orig:
+      - [onephrase, 100]
+      - [and, 50]
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^450
+#    QueryFields:
+#      - title_full_unstemmed:
+#        - [onephrase, 450]
+#        - [and, 400]
+
+Series:
+  DismaxFields:
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    - series:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+    - series2:
+      - [onephrase, 50]
+      - [and, 50]
+      - [or, ~]
+    - series_orig:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+
+Series2:
+  DismaxFields:
+    - series2
+  QueryFields:
+    - series2:
+      - [onephrase, 200]
+      - [and, 50]
+
+AllFields:
+  DismaxParams:
+    - [mm, 3]
+    - [bf , ord(publishDateSort)^10]
+    - [bf , "if(exists(query({!v='source_id:0'})),10,1)^1000"]
+#    - [bf, "if(exists(query({!v='access_facet:Local*'})),10,1)^1000"]
+  DismaxFields:
+    - title_short^1000
+    - title_full_unstemmed^1000
+    - title_full^400
+    - title^500
+    - title_alt^200
+    - title_new^100
+    - title_orig^500
+    - series^50
+    - series2^30
+    - series_orig^50
+    - author^500
+    - author_corp^300
+    - author2^400
+    - author_corp2^100
+    - author_ref^500
+    - author_corp_ref^500
+    - author_orig^300
+    - author2_orig^300
+    - author_corp_orig^300
+    - author_corp2_orig^100
+    - topic_ref^10
+    - contents^10
+    - topic_unstemmed^15
+    - topic^10
+    - geographic^10
+    - genre^10
+    - rvk_label
+    - allfields_unstemmed^10
+    - allfields
+    - fulltext
+    - isbn
+    - issn
+    - ismn
+
+  QueryFields:
+    0:
+      0:
+        - OR
+        - 50
+      title_short:
+        - [onephrase, 1000]
+      title_full_unstemmed:
+        - [onephrase, 1000]
+        - [and, 500]
+      title_full:
+        - [onephrase, 400]
+      title:
+        - [onephrase, 300]
+        - [and, 250]
+      title_alt:
+        - [and, 200]
+      title_new:
+        - [and, 100]
+      title_orig:
+        - [onephrase, 500]
+        - [and, 400]
+    series:
+      - [onephrase, 300]
+      - [and, 100]
+    series2:
+      - [and, 30]
+    series_orig:
+      - [onephrase, 200]
+      - [and, 100]
+    author:
+      - [onephrase, 500]
+      - [and, 250]
+    author_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_corp_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_orig:
+      - [onephrase, 500]
+      - [and, 250]
+    author2_orig:
+      - [and, 50]
+    author_corp_orig:
+      - [onephrase, 500]
+      - [and, 400]
+    author_corp2_orig:
+      - [and, 50]
+    author_corp:
+      - [onephrase, 500]
+      - [and, 400]
+    author2:
+      - [and, 50]
+    author_corp2:
+      - [and, 50]
+    contents:
+      - [and, 10]
+    topic_unstemmed:
+      - [onephrase, 55]
+      - [and, 50]
+    topic:
+      - [onephrase, 50]
+    topic_ref:
+      - [onephrase, 10]
+      - [and, 5]
+      - [or, 5]
+    topic_id:
+      - [onephrase, 50]
+      - [and, 25]
+    allfields_unstemmed:
+      - [or, 10]
+    allfields:
+      - [or, ~]
+    fulltext:
+      - [or, ~]
+    rvk_label:
+      - [onephrase, 500]
+      - [and, 250]
+      - [or, 250]
+    isbn:
+      - [onephrase, 500]
+    issn:
+      - [onephrase, 500]
+    ismn:
+      - [onephrase, 500]
+    imprint:
+      - [onephrase, 500]
+      
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^600
+#      - topic_unstemmed^550
+#      - allfields_unstemmed^10
+#      - fulltext_unstemmed^10
+#      - isbn
+#      - issn
+#    QueryFields:
+#      title_full_unstemmed:
+#        - [onephrase, 600]
+#        - [and, 500]
+#      topic_unstemmed:
+#        - [onephrase, 550]
+#        - [and, 500]
+#      allfields_unstemmed:
+#        - [or, 10]
+#      fulltext_unstemmed:
+#        - [or, 10]
+#      isbn:
+#        - [onephrase, ~]
+#      issn:
+#        - [onephrase, ~]
+
+# These are advanced searches that never use Dismax:
+id:
+  QueryFields:
+    - id:
+      - [onephrase, ~]
+
+# Fields for exact matches originating from alphabetic browse
+ids:
+  QueryFields:
+    - id:
+      - [or, ~]
+
+TopicBrowse:
+  QueryFields:
+    - topic_browse:
+      - [onephrase, ~]
+
+AuthorBrowse:
+  QueryFields:
+    - author_browse:
+      - [onephrase, ~]
+
+TitleBrowse:
+  QueryFields:
+    - title_full:
+      - [onephrase, ~]
+
+DeweyBrowse:
+  QueryFields:
+    - dewey-raw:
+      - [onephrase, ~]
+
+LccBrowse:
+  QueryFields:
+    - callnumber-a:
+      - [onephrase, ~]
+
+
+
+# CallNumber:
+  # We use two similar munges here -- one for exact matches, which will get
+  # a very high boost factor, and one for left-anchored wildcard searches,
+  # which will return a larger number of hits at a lower boost.
+  #CustomMunge:
+    #callnumber_exact:
+      #- [uppercase]
+      # Strip whitespace and quotes:
+      #- [preg_replace, '/[ "]/', ""]
+      # Escape colons (unescape first to avoid double-escapes):
+      #- [preg_replace, "/(\\\:)/", ':']
+      #- [preg_replace, '/:/', '\:']
+      # Strip pre-existing trailing asterisks:
+      #- [preg_replace, "/\*+$/", ""]
+    #callnumber_fuzzy:
+      #- [uppercase]
+      # Strip whitespace and quotes:
+      #- [preg_replace, '/[ "]/', ""]
+      # Escape colons (unescape first to avoid double-escapes):
+      #- [preg_replace, "/(\\\:)/", ':']
+      #- [preg_replace, '/:/', '\:']
+      # Strip pre-existing trailing asterisks, then add a new one:
+      #- [preg_replace, "/\*+$/", ""]
+      #- [append, "*"]
+  QueryFields:
+    callnumber-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, ~]
+    dewey-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, ~]
+
+publisher:
+  DismaxFields:
+    - publisher^100
+  QueryFields:
+    - publisher:
+      - [and, 100]
+      - [or, ~]
+
+year:
+  DismaxFields:
+    - publishDate^100
+  QueryFields:
+    - publishDate:
+      - [and, 100]
+      - [or, ~]
+
+language:
+  QueryFields:
+    - language:
+      - [and, ~]
+
+toc:
+  DismaxFields:
+    - contents^100
+  QueryFields:
+    - contents:
+      - [and, 100]
+      - [or, ~]
+
+topic:
+  QueryFields:
+    - topic:
+      - [and, 50]
+    - topic_facet:
+      - [and, ~]
+
+geographic:
+  QueryFields:
+    - geographic:
+      - [and, 50]
+    - geographic_facet:
+      - [and ~]
+
+genre:
+  QueryFields:
+    - genre:
+      - [and, 50]
+    - genre_facet:
+      - [and, ~]
+
+era:
+  QueryFields:
+    - era:
+      - [and, ~]
+
+oclc_num:
+  CustomMunge:
+    oclc_num:
+      - [preg_replace, "/[^0-9]/", ""]
+      # trim leading zeroes:
+      - [preg_replace, "/^0*/", ""]
+  QueryFields:
+    - oclc_num:
+      - [oclc_num, ~]
+      
+rvk:
+  DismaxFields:
+    - rvk_facet^100
+  QueryFields:
+    - rvk_facet:
+      - [and, 50]
+      - [or, 50]
+      
+rvk_path:
+  QueryFields:
+    - rvk_path:
+      - [onephrase, ~]
+
+multipart:
+  DismaxFields:
+    - multipart_link^100
+  QueryFields:
+    - multipart_link:
+      - [and, 50]
+      - [or, 50]  
diff --git a/local/config/vufind/searchspecs.yaml b/local/config/vufind/searchspecs.yaml
index 52fd75dd3ab..498d584b19e 100644
--- a/local/config/vufind/searchspecs.yaml
+++ b/local/config/vufind/searchspecs.yaml
@@ -155,11 +155,12 @@ Author:
   DismaxParams:
     - [bf , ord(publishDateSort)^10]
   DismaxFields:
-    - author^200
-    - author2^200
+    - author^400
+    - author2^300
     - author_id^100
     - author_ref^150
     - author_corp^200
+    - author_corp2^200
     - author_corp_ref^150
     - author_orig^200
     - author2_orig^200
@@ -182,6 +183,10 @@ Author:
       - [onephrase, 350]
       - [and, 200]
       - [or, 100]
+    - author_corp2:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
     - author_corp_ref:
       - [onephrase, 350]
       - [and, 200]
@@ -227,9 +232,9 @@ Signatur:
   DismaxParams:
     - [mm, 0]
   DismaxFields:
-    - signatur
+    - callnumber_ISIL
   QueryFields:
-    - signatur:
+    - callnumber_ISIL:
       - [or, ~]
   #    - [and, 100]
   #    - [or, ~]
@@ -238,9 +243,9 @@ Barcode:
   DismaxParams:
     - [mm, 0]
   DismaxFields:
-    - barcode
+    - barcode_ISIL
   QueryFields:
-    - barcode:
+    - barcode_ISIL:
       #- [and, 100]
       - [or, ~]
 
@@ -263,12 +268,12 @@ Subject:
       - [and, 100]
       - [or, ~]
     - topic_ref:
-      - [onephrase, 300]
-      - [and, 100]
+      - [onephrase, 100]
+      - [and, 50]
       - [or, ~]
     - topic_id:
-      - [onephrase, 300]
-      - [and, 100]
+      - [onephrase, 100]
+      - [and, 50]
       - [or, ~]
     #- geographic:
     #  - [onephrase, 300]
@@ -341,6 +346,7 @@ JournalTitle:
 
 Title:
   DismaxParams:
+    - [mm, 3]
     - [bf , ord(publishDateSort)^10]
   DismaxFields:
 #    - title_sub^200
@@ -423,9 +429,11 @@ AllFields:
   DismaxParams:
     - [mm, 3]
     - [bf , ord(publishDateSort)^10]
+    - [bf , "if(exists(query({!v='source_id:0'})),10,1)^1000"]
+#    - [bf, "if(exists(query({!v='access_facet:Local*'})),10,1)^1000"]
   DismaxFields:
-    - title_short^750
-    - title_full_unstemmed^600
+    - title_short^1000
+    - title_full_unstemmed^1000
     - title_full^400
     - title^500
     - title_alt^200
@@ -434,24 +442,22 @@ AllFields:
     - series^50
     - series2^30
     - series_orig^50
-    - author^300
-    - author_id^100
+    - author^500
     - author_corp^300
-    - author2^300
+    - author2^400
     - author_corp2^100
-    - author_fuller^150
     - author_ref^500
     - author_corp_ref^500
     - author_orig^300
     - author2_orig^300
     - author_corp_orig^300
     - author_corp2_orig^100
-    - topic_ref^500
+    - topic_ref^10
     - contents^10
-    - topic_unstemmed^550
-    - topic^500
-    - geographic^300
-    - genre^300
+    - topic_unstemmed^15
+    - topic^10
+    - geographic^10
+    - genre^10
     - rvk_label
     - allfields_unstemmed^10
     - allfields
@@ -459,16 +465,16 @@ AllFields:
     - isbn
     - issn
     - ismn
-    - rsn
+
   QueryFields:
     0:
       0:
         - OR
         - 50
       title_short:
-        - [onephrase, 750]
+        - [onephrase, 1000]
       title_full_unstemmed:
-        - [onephrase, 600]
+        - [onephrase, 1000]
         - [and, 500]
       title_full:
         - [onephrase, 400]
@@ -493,15 +499,12 @@ AllFields:
     author:
       - [onephrase, 500]
       - [and, 250]
-    author_id:
-      - [onephrase, 50]
-      - [and, 25]
     author_ref:
-      - [onephrase, 500]
+      - [onephrase, 250]
       - [and, 250]
       - [or, 250]
     author_corp_ref:
-      - [onephrase, 500]
+      - [onephrase, 250]
       - [and, 250]
       - [or, 250]
     author_orig:
@@ -524,14 +527,14 @@ AllFields:
     contents:
       - [and, 10]
     topic_unstemmed:
-      - [onephrase, 550]
-      - [and, 500]
+      - [onephrase, 55]
+      - [and, 50]
     topic:
-      - [onephrase, 500]
+      - [onephrase, 50]
     topic_ref:
-      - [onephrase, 500]
-      - [and, 250]
-      - [or, 250]
+      - [onephrase, 10]
+      - [and, 5]
+      - [or, 5]
     topic_id:
       - [onephrase, 50]
       - [and, 25]
@@ -541,12 +544,19 @@ AllFields:
       - [or, ~]
     fulltext:
       - [or, ~]
+    rvk_label:
+      - [onephrase, 500]
+      - [and, 250]
+      - [or, 250]
     isbn:
       - [onephrase, 500]
     issn:
       - [onephrase, 500]
     ismn:
       - [onephrase, 500]
+    imprint:
+      - [onephrase, 500]
+      
 #  ExactSettings:
 #    DismaxFields:
 #      - title_full_unstemmed^600
diff --git a/local/dev/config/vufind/searchspecs.yaml.sample b/local/dev/config/vufind/searchspecs.yaml.sample
new file mode 100644
index 00000000000..498d584b19e
--- /dev/null
+++ b/local/dev/config/vufind/searchspecs.yaml.sample
@@ -0,0 +1,739 @@
+---
+# Listing of search types and their component parts and weights.
+#
+# Format is:
+#  searchType:
+#    # CustomMunge is an optional section to define custom pre-processing of
+#    #     user input.  See below for details of munge actions.
+#    CustomMunge:
+#      MungeName1:
+#        - [action1, actionParams]
+#        - [action2, actionParams]
+#        - [action3, actionParams]
+#      MungeName2:
+#        - [action1, actionParams]
+#    # DismaxFields is optional and defines the fields sent to the Dismax handler
+#    #     when we are able to use it.  QueryFields will be used for advanced
+#    #     searches that Dismax cannot support.  QueryFields is always used if no
+#    #     DismaxFields section is defined.
+#    DismaxFields:
+#      - field1^boost
+#      - field2^boost
+#      - field3^boost
+#    # DismaxParams is optional and allows you to override default Dismax settings
+#    #     (i.e. mm / bf) on a search-by-search basis. Enclose the parameter values
+#    #     in quotes for proper behavior. If you want global default values for these
+#    #     settings, you can edit the appropriate search handler in
+#    #     solr/biblio/conf/solrconfig.xml.
+#    DismaxParams:
+#      - [param1_name, param1_value]
+#      - [param2_name, param2_value]
+#      - [param3_name, param3_value]
+#    # This optional setting may be used to specify which Dismax handler to use. By
+#    #     default, VuFind provides two options: dismax (for the old, standard
+#    #     Dismax) and edismax (for Extended Dismax). You can also configure your own
+#    #     in solrconfig.xml, but VuFind relies on the name "edismax" to identify an
+#    #     Extended Dismax handler. If you omit this setting, the default value from
+#    #     the default_dismax_handler setting in the [Index] section of config.ini
+#    #     will be used.
+#    DismaxHandler: dismax|edismax
+#    # QueryFields define the fields we are searching when not using Dismax; VuFind
+#    #     detects queries that will not work with Dismax and switches to QueryFields
+#    #     as needed.
+#    QueryFields:
+#      SolrField:
+#        - [howToMungeSearchstring, weight]
+#        - [differentMunge, weight]
+#      DifferentSolrField:
+#        - [howToMunge, weight]
+#    # The optional FilterQuery section allows you to AND a static query to the
+#    #     dynamic query generated using the QueryFields; see JournalTitle below
+#    #     for an example.  This is applied whether we use DismaxFields or
+#    #     QueryFields.
+#    FilterQuery: (optional Lucene filter query)
+#    ExactSettings:
+#      DismaxFields: ...
+#      QueryFields: ...
+#    # All the same settings as above, but for exact searches, i.e. search terms
+#    #     enclosed in quotes. Allows different fields or weights for exact
+#    #     searches. See below for commented-out examples.
+#
+# ...etc.
+#
+#-----------------------------------------------------------------------------------
+#
+# Within the QueryFields area, fields are OR'd together, unless they're in an
+# anonymous array with a numeric instead of alphanumeric key, in which case the
+# first element is a two-value array that tells us what the type (AND or OR) and
+# weight of the whole group should be.
+#
+# So, given:
+#
+# test:
+#   QueryFields:
+#     A:
+#       - [onephrase, 500]
+#       - [and, 200]
+#     B:
+#       - [and, 100]
+#       - [or, 50]
+#     # Start an anonymous array to group; first element indicates AND grouping
+#     #     and a weight of 50
+#     0:
+#       0:
+#         - AND
+#         - 50
+#       C:
+#         - [onephrase, 200]
+#       D:
+#         - [onephrase, 300]
+#       # Note the "not" attached to the field name as a minus, and the use of ~
+#       #     to mean null ("no special weight")
+#       -E:
+#         - [or, ~]
+#     D:
+#       - [or, 100]
+#
+#  ...and the search string
+#
+#      test "one two"
+#
+#  ...we'd get
+#
+#   (A:"test one two"^500 OR
+#    A:(test AND "one two")^ 200 OR
+#    B:(test AND "one two")^100 OR
+#    B:(test OR "one two")^50
+#    (
+#      C:("test one two")^200 AND
+#      D:"test one two"^300 AND
+#      -E:(test OR "one two")
+#    )^50 OR
+#    D:(test OR "one two")^100
+#   )
+#
+#-----------------------------------------------------------------------------------
+#
+# Munge types are based on the original Solr.php code, and consist of:
+#
+# onephrase: eliminate all quotes and do it as a single phrase. 
+#   testing "one two"
+#    ...becomes ("testing one two")
+#
+# and: AND the terms together
+#  testing "one two"
+#   ...becomes (testing AND "one two")
+#
+# or: OR the terms together
+#  testing "one two"
+#   ...becomes (testing OR "one two")
+#
+# identity: Use the search as-is
+#  testing "one two"
+#   ...becomes (testing "one two")
+#
+# Additional Munge types can be defined in the CustomMunge section.  Each array
+# entry under CustomMunge defines a new named munge type.  Each array entry under
+# the name of the munge type specifies a string manipulation operation.  Operations
+# will be applied in the order listed, and different operations take different
+# numbers of parameters.
+#
+# Munge operations:
+#
+# [append, text] - Append text to the end of the user's search string
+# [lowercase] - Convert string to lowercase
+# [preg_replace, pattern, replacement] - Perform a regular expression replace
+#     using the preg_replace() PHP function.  If you use backreferences in your
+#     replacement phrase, be sure to escape dollar signs (i.e. \$1, not $1).
+# [uppercase] - Convert string to uppercase
+#
+# See the CallNumber search below for an example of custom munging in action.
+#-----------------------------------------------------------------------------------
+
+# These searches use Dismax when possible:
+Author:
+  DismaxParams:
+    - [bf , ord(publishDateSort)^10]
+  DismaxFields:
+    - author^400
+    - author2^300
+    - author_id^100
+    - author_ref^150
+    - author_corp^200
+    - author_corp2^200
+    - author_corp_ref^150
+    - author_orig^200
+    - author2_orig^200
+    - author_corp_orig^200
+    - author_corp2_orig^200
+  QueryFields:
+    - author:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author2:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    - author_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp2:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_corp2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    - author_id:
+      - [onephrase, 450]
+      - [and, 300]
+      - [or, 200]
+
+ISN:
+#  DismaxFields:
+#    - isbn
+#    - issn
+#    - ismn
+  QueryFields:
+    - issn:
+      - [and, 100]
+      - [or, ~]
+    - isbn:
+      - [and, 100]
+      - [or, ~]
+    - ismn:
+      - [and, 100]
+      - [or, ~]
+
+Signatur:
+  DismaxParams:
+    - [mm, 0]
+  DismaxFields:
+    - callnumber_ISIL
+  QueryFields:
+    - callnumber_ISIL:
+      - [or, ~]
+  #    - [and, 100]
+  #    - [or, ~]
+
+Barcode:
+  DismaxParams:
+    - [mm, 0]
+  DismaxFields:
+    - barcode_ISIL
+  QueryFields:
+    - barcode_ISIL:
+      #- [and, 100]
+      - [or, ~]
+
+Subject:
+  DismaxFields:
+    - topic_unstemmed^150
+    - topic^100
+    - topic_id^100
+    - topic_ref^100
+    #- geographic^50
+    #- genre^50
+    #- era
+  QueryFields:
+    - topic_unstemmed:
+      - [onephrase, 350]
+      - [and, 150]
+      - [or, ~]
+    - topic:
+      - [onephrase, 300]
+      - [and, 100]
+      - [or, ~]
+    - topic_ref:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    - topic_id:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, ~]
+    #- geographic:
+    #  - [onephrase, 300]
+    #  - [and, 100]
+    #  - [or, ~]
+    #- genre:
+    #  - [onephrase, 300]
+    #  - [and, 100]
+    #  - [or, ~]
+    #- era:
+    #  - [and, 100]
+    #  - [or, ~]
+#  ExactSettings:
+#    DismaxFields:
+#      - topic_unstemmed^150
+#    QueryFields:
+#      - topic_unstemmed:
+#        - [onephrase, 350]
+#        - [and, 150]
+#        - [or, ~]
+
+# This field definition is a compromise that supports both journal-level and
+# article-level data.  The disadvantage is that hits in article titles will
+# be mixed in.  If you are building a purely article-oriented index, you should
+# customize this to remove all of the title_* fields and focus entirely on the
+# container_title field.
+JournalTitle:
+  DismaxFields:
+    - title_short^500
+    - title_full_unstemmed^450
+    - title_full^400
+    - title^300
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - series^100
+    - series2
+  QueryFields:
+    - title_short:
+      - [onephrase, 500]
+    - title_full_unstemmed:
+      - [onephrase, 450]
+      - [and, 400]
+    - title_full:
+      - [onephrase, 400]
+    - title:
+      - [onephrase, 300]
+      - [and, 250]
+    - title_alt:
+      - [and, 200]
+    - title_new:
+      - [and, 100]
+    - title_old:
+      - [and, ~]  
+    - series:
+      - [onephrase, 100]
+      - [and, 50]
+    - series2:
+      - [onephrase, 50]
+      - [and , ~]
+  FilterQuery: "format:Journal"
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^450
+#    QueryFields:
+#      - title_full_unstemmed:
+#        - [onephrase, 450]
+#        - [and, 400]
+#    FilterQuery: "format:Journal OR format:Article"
+
+Title:
+  DismaxParams:
+    - [mm, 3]
+    - [bf , ord(publishDateSort)^10]
+  DismaxFields:
+#    - title_sub^200
+#    - title_short^300
+    - title_full_unstemmed^150
+    - title_full^100
+    - title^900
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - title_orig^400
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    - title_short:
+      - [onephrase, 500]
+    - title_full_unstemmed:
+      - [onephrase, 150]
+      - [and, 100]
+    - title_full:
+      - [onephrase, 100]
+    - title:
+      - [onephrase, 300]
+      - [and, 250]
+    - title_alt:
+      - [and, 200]
+    - title_new:
+      - [and, 100]
+    - title_old:
+      - [and, ~]
+    - title_orig:
+      - [onephrase, 500]
+      - [and, 200]
+    - series:
+      - [onephrase, 100]
+      - [and, 50]
+    - series2:
+      - [onephrase, 50]
+      - [and , ~]
+    - series_orig:
+      - [onephrase, 100]
+      - [and, 50]
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^450
+#    QueryFields:
+#      - title_full_unstemmed:
+#        - [onephrase, 450]
+#        - [and, 400]
+
+Series:
+  DismaxFields:
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    - series:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+    - series2:
+      - [onephrase, 50]
+      - [and, 50]
+      - [or, ~]
+    - series_orig:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+
+Series2:
+  DismaxFields:
+    - series2
+  QueryFields:
+    - series2:
+      - [onephrase, 200]
+      - [and, 50]
+
+AllFields:
+  DismaxParams:
+    - [mm, 3]
+    - [bf , ord(publishDateSort)^10]
+    - [bf , "if(exists(query({!v='source_id:0'})),10,1)^1000"]
+#    - [bf, "if(exists(query({!v='access_facet:Local*'})),10,1)^1000"]
+  DismaxFields:
+    - title_short^1000
+    - title_full_unstemmed^1000
+    - title_full^400
+    - title^500
+    - title_alt^200
+    - title_new^100
+    - title_orig^500
+    - series^50
+    - series2^30
+    - series_orig^50
+    - author^500
+    - author_corp^300
+    - author2^400
+    - author_corp2^100
+    - author_ref^500
+    - author_corp_ref^500
+    - author_orig^300
+    - author2_orig^300
+    - author_corp_orig^300
+    - author_corp2_orig^100
+    - topic_ref^10
+    - contents^10
+    - topic_unstemmed^15
+    - topic^10
+    - geographic^10
+    - genre^10
+    - rvk_label
+    - allfields_unstemmed^10
+    - allfields
+    - fulltext
+    - isbn
+    - issn
+    - ismn
+
+  QueryFields:
+    0:
+      0:
+        - OR
+        - 50
+      title_short:
+        - [onephrase, 1000]
+      title_full_unstemmed:
+        - [onephrase, 1000]
+        - [and, 500]
+      title_full:
+        - [onephrase, 400]
+      title:
+        - [onephrase, 300]
+        - [and, 250]
+      title_alt:
+        - [and, 200]
+      title_new:
+        - [and, 100]
+      title_orig:
+        - [onephrase, 500]
+        - [and, 400]
+    series:
+      - [onephrase, 300]
+      - [and, 100]
+    series2:
+      - [and, 30]
+    series_orig:
+      - [onephrase, 200]
+      - [and, 100]
+    author:
+      - [onephrase, 500]
+      - [and, 250]
+    author_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_corp_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_orig:
+      - [onephrase, 500]
+      - [and, 250]
+    author2_orig:
+      - [and, 50]
+    author_corp_orig:
+      - [onephrase, 500]
+      - [and, 400]
+    author_corp2_orig:
+      - [and, 50]
+    author_corp:
+      - [onephrase, 500]
+      - [and, 400]
+    author2:
+      - [and, 50]
+    author_corp2:
+      - [and, 50]
+    contents:
+      - [and, 10]
+    topic_unstemmed:
+      - [onephrase, 55]
+      - [and, 50]
+    topic:
+      - [onephrase, 50]
+    topic_ref:
+      - [onephrase, 10]
+      - [and, 5]
+      - [or, 5]
+    topic_id:
+      - [onephrase, 50]
+      - [and, 25]
+    allfields_unstemmed:
+      - [or, 10]
+    allfields:
+      - [or, ~]
+    fulltext:
+      - [or, ~]
+    rvk_label:
+      - [onephrase, 500]
+      - [and, 250]
+      - [or, 250]
+    isbn:
+      - [onephrase, 500]
+    issn:
+      - [onephrase, 500]
+    ismn:
+      - [onephrase, 500]
+    imprint:
+      - [onephrase, 500]
+      
+#  ExactSettings:
+#    DismaxFields:
+#      - title_full_unstemmed^600
+#      - topic_unstemmed^550
+#      - allfields_unstemmed^10
+#      - fulltext_unstemmed^10
+#      - isbn
+#      - issn
+#    QueryFields:
+#      title_full_unstemmed:
+#        - [onephrase, 600]
+#        - [and, 500]
+#      topic_unstemmed:
+#        - [onephrase, 550]
+#        - [and, 500]
+#      allfields_unstemmed:
+#        - [or, 10]
+#      fulltext_unstemmed:
+#        - [or, 10]
+#      isbn:
+#        - [onephrase, ~]
+#      issn:
+#        - [onephrase, ~]
+
+# These are advanced searches that never use Dismax:
+id:
+  QueryFields:
+    - id:
+      - [onephrase, ~]
+
+# Fields for exact matches originating from alphabetic browse
+ids:
+  QueryFields:
+    - id:
+      - [or, ~]
+
+TopicBrowse:
+  QueryFields:
+    - topic_browse:
+      - [onephrase, ~]
+
+AuthorBrowse:
+  QueryFields:
+    - author_browse:
+      - [onephrase, ~]
+
+TitleBrowse:
+  QueryFields:
+    - title_full:
+      - [onephrase, ~]
+
+DeweyBrowse:
+  QueryFields:
+    - dewey-raw:
+      - [onephrase, ~]
+
+LccBrowse:
+  QueryFields:
+    - callnumber-a:
+      - [onephrase, ~]
+
+
+
+# CallNumber:
+  # We use two similar munges here -- one for exact matches, which will get
+  # a very high boost factor, and one for left-anchored wildcard searches,
+  # which will return a larger number of hits at a lower boost.
+  #CustomMunge:
+    #callnumber_exact:
+      #- [uppercase]
+      # Strip whitespace and quotes:
+      #- [preg_replace, '/[ "]/', ""]
+      # Escape colons (unescape first to avoid double-escapes):
+      #- [preg_replace, "/(\\\:)/", ':']
+      #- [preg_replace, '/:/', '\:']
+      # Strip pre-existing trailing asterisks:
+      #- [preg_replace, "/\*+$/", ""]
+    #callnumber_fuzzy:
+      #- [uppercase]
+      # Strip whitespace and quotes:
+      #- [preg_replace, '/[ "]/', ""]
+      # Escape colons (unescape first to avoid double-escapes):
+      #- [preg_replace, "/(\\\:)/", ':']
+      #- [preg_replace, '/:/', '\:']
+      # Strip pre-existing trailing asterisks, then add a new one:
+      #- [preg_replace, "/\*+$/", ""]
+      #- [append, "*"]
+  QueryFields:
+    callnumber-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, ~]
+    dewey-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, ~]
+
+publisher:
+  DismaxFields:
+    - publisher^100
+  QueryFields:
+    - publisher:
+      - [and, 100]
+      - [or, ~]
+
+year:
+  DismaxFields:
+    - publishDate^100
+  QueryFields:
+    - publishDate:
+      - [and, 100]
+      - [or, ~]
+
+language:
+  QueryFields:
+    - language:
+      - [and, ~]
+
+toc:
+  DismaxFields:
+    - contents^100
+  QueryFields:
+    - contents:
+      - [and, 100]
+      - [or, ~]
+
+topic:
+  QueryFields:
+    - topic:
+      - [and, 50]
+    - topic_facet:
+      - [and, ~]
+
+geographic:
+  QueryFields:
+    - geographic:
+      - [and, 50]
+    - geographic_facet:
+      - [and ~]
+
+genre:
+  QueryFields:
+    - genre:
+      - [and, 50]
+    - genre_facet:
+      - [and, ~]
+
+era:
+  QueryFields:
+    - era:
+      - [and, ~]
+
+oclc_num:
+  CustomMunge:
+    oclc_num:
+      - [preg_replace, "/[^0-9]/", ""]
+      # trim leading zeroes:
+      - [preg_replace, "/^0*/", ""]
+  QueryFields:
+    - oclc_num:
+      - [oclc_num, ~]
+      
+rvk:
+  DismaxFields:
+    - rvk_facet^100
+  QueryFields:
+    - rvk_facet:
+      - [and, 50]
+      - [or, 50]
+      
+rvk_path:
+  QueryFields:
+    - rvk_path:
+      - [onephrase, ~]
+
+multipart:
+  DismaxFields:
+    - multipart_link^100
+  QueryFields:
+    - multipart_link:
+      - [and, 50]
+      - [or, 50]  
diff --git a/module/finc/src/finc/RecordDriver/SolrDefault.php b/module/finc/src/finc/RecordDriver/SolrDefault.php
index f619e72812b..ce4b3bbd46c 100644
--- a/module/finc/src/finc/RecordDriver/SolrDefault.php
+++ b/module/finc/src/finc/RecordDriver/SolrDefault.php
@@ -52,4 +52,33 @@ class SolrDefault extends \VuFind\RecordDriver\SolrDefault implements
 {
     use \VuFind\Log\LoggerAwareTrait;
     use SolrDefaultFincTrait;
+
+    /**
+     * Index extension used for dynamic fields
+     *
+     * @var string
+     */
+    protected $indexExtension = '';
+
+    /**
+     * Constructor
+     *
+     * @param \Zend\Config\Config $mainConfig     VuFind main configuration (omit for
+     * built-in defaults)
+     * @param \Zend\Config\Config $recordConfig   Record-specific configuration file
+     * (omit to use $mainConfig as $recordConfig)
+     * @param \Zend\Config\Config $searchSettings Search-specific configuration file
+     */
+    public function __construct($mainConfig = null, $recordConfig = null,
+                                $searchSettings = null
+    )
+    {
+        parent::__construct($mainConfig, $recordConfig, $searchSettings);
+
+        if (isset($this->mainConfig->CustomIndex->indexExtension)) {
+            $this->indexExtension = $this->mainConfig->CustomIndex->indexExtension;
+        } else {
+            $this->debug('Index extension for custom index not set!');
+        }
+    }
 }
diff --git a/module/finc/src/finc/RecordDriver/SolrDefaultFincTrait.php b/module/finc/src/finc/RecordDriver/SolrDefaultFincTrait.php
index 0ec2e010c52..2e27f68e0f2 100644
--- a/module/finc/src/finc/RecordDriver/SolrDefaultFincTrait.php
+++ b/module/finc/src/finc/RecordDriver/SolrDefaultFincTrait.php
@@ -50,6 +50,18 @@ use VuFindSearch\ParamBag;
 trait SolrDefaultFincTrait
 {
 
+    /**
+     * Get all call numbers associated with the record (empty string if none).
+     *
+     * @return array
+     */
+    public function getCallNumbers()
+    {
+        return isset($this->fields['callnumber_' . $this->indexExtension])
+            ? $this->fields['callnumber_' . $this->indexExtension]
+            : parent::getCallNumbers();
+    }
+
     /**
      * Return the custom index field local_heading if indexExtension is set.
      * If indexExtension is set local_heading_{indexExtension} is returned,
diff --git a/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php b/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
index 381e4f21ec6..178ff5dd7e8 100644
--- a/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
+++ b/module/finc/src/finc/RecordDriver/SolrMarcFincTrait.php
@@ -168,6 +168,7 @@ trait SolrMarcFincTrait
      *
      * @return array   Return fields.
      * @access public
+     * @deprecated (https://intern.finc.info/issues/6324)
      * @link   https://intern.finc.info/issues/2639
      */
     public function getLocalCallnumber()
@@ -198,6 +199,7 @@ trait SolrMarcFincTrait
      *
      * @return array
      * @access protected
+     * @deprecated (https://intern.finc.info/issues/6324)
      */
     protected function getLocalCallnumbersByLibrary()
     {
-- 
GitLab