{"id":23122811,"url":"https://github.com/folio-org/mod-search","last_synced_at":"2026-01-19T17:01:13.706Z","repository":{"id":37769952,"uuid":"317258394","full_name":"folio-org/mod-search","owner":"folio-org","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-12T17:01:02.000Z","size":5841,"stargazers_count":6,"open_issues_count":2,"forks_count":8,"subscribers_count":17,"default_branch":"master","last_synced_at":"2026-01-12T19:48:36.150Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/folio-org.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-11-30T15:02:14.000Z","updated_at":"2026-01-12T12:48:09.000Z","dependencies_parsed_at":"2023-12-12T11:28:38.104Z","dependency_job_id":"f144bb60-95e1-4b93-8eaf-a2793581cbb1","html_url":"https://github.com/folio-org/mod-search","commit_stats":null,"previous_names":[],"tags_count":81,"template":false,"template_full_name":null,"purl":"pkg:github/folio-org/mod-search","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Fmod-search","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Fmod-search/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Fmod-search/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Fmod-search/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/folio-org","download_url":"https://codeload.github.com/folio-org/mod-search/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Fmod-search/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28577027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T16:29:19.148Z","status":"ssl_error","status_checked_at":"2026-01-19T16:29:17.772Z","response_time":67,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-17T07:30:37.311Z","updated_at":"2026-01-19T17:01:13.697Z","avatar_url":"https://github.com/folio-org.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mod-search\n\nCopyright (C) 2020-2023 The Open Library Foundation\n\nThis software is distributed under the terms of the Apache License,\nVersion 2.0. See the file \"[LICENSE](LICENSE)\" for more information.\n\n## Table of contents\n\n- [Introduction](#introduction)\n- [Compiling](#compiling)\n- [Running it](#running-it)\n- [Docker](#docker)\n- [Multi-language search support](#multi-language-search-support)\n  * [Adding new languages via REST](#adding-new-languages-via-rest)\n  * [Defining initial languages via ENV variable](#defining-initial-languages-via-env-variable)\n- [Deploying the module](#deploying-the-module)\n  * [Configuring Elasticsearch](#configuring-elasticsearch)\n    + [Configuring on-premise Elasticsearch instance](#configuring-on-premise-elasticsearch-instance)\n    + [Recommended production set-up](#recommended-production-set-up)\n  * [Environment variables](#environment-variables)\n  * [Configuring spring-boot using JAVA_OPTIONS](#configuring-spring-boot)\n  * [Configuring connection to elasticsearch](#configuring-connection-to-elasticsearch)\n  * [Tenant attributes](#tenant-attributes)\n- [Data Indexing](#data-indexing)\n  * [Recreating Elasticsearch index](#recreating-elasticsearch-index)\n  * [Updating index settings](#updating-index-settings)\n  * [Monitoring reindex process](#monitoring-reindex-process)\n- [Indexing of Instance Records](#indexing-of-instance-records)\n- [API](#api)\n  * [CQL support](#cql-support)\n    + [CQL query operators](#cql-query-operators)\n    + [CQL query modifiers](#cql-query-modifiers)\n  * [Search API](#search-api)\n    + [Searching and filtering](#searching-and-filtering)\n      - [Matching all records](#matching-all-records)\n      - [Matching undefined or empty values](#matching-undefined-or-empty-values)\n      - [Search by all field values](#search-by-all-field-values)\n      - [Instance search options](#instance-search-options)\n      - [Holdings search options](#holdings-search-options)\n      - [Item search options](#item-search-options)\n      - [Authority search options](#authority-search-options)\n      - [Contributors search options](#contributors-search-options)\n    + [Search Facets](#search-facets)\n      - [Instance facets](#instance-facets)\n      - [Holdings facets](#holdings-facets)\n      - [Item facets](#item-facets)\n      - [Authority facets](#authority-facets)\n      - [Contributors facets](#contributors-facets)\n    + [Sorting results](#sorting-results)\n      - [Instance sort options](#instance-sort-options)\n      - [Authority sort options](#authority-sort-options)\n  * [Browse API](#browse-api)\n  * [Resource IDs streaming API](#resource-ids-streaming-api)\n    + [Create Job](#create-job)\n    + [Retrieve ids](#retrieve-ids)\n- [Additional Information](#additional-information)\n  * [Issue tracker](#issue-tracker)\n  * [API Documentation](#api-documentation)\n  * [Code analysis](#code-analysis)\n  * [Download and configuration](#download-and-configuration)\n  * [Development tips](#development-tips)\n\n## Introduction\n\nThis module provides a search functionality for instance and authorities via REST API. It uses\n[The Contextual Query Language](https://www.loc.gov/standards/sru/cql/) as a formal language to query\nrecords using filters, boolean conditions, etc.\n\nmod-search works with either Elasticsearch and OpenSearch, however,\nmany variables still have Elasticsearch in their name for backwards compatibility.\n\n![Full Reindex](doc/diagrams/full-reindex.png)\n\n## Compiling\n\n```shell\nmvn install\n```\n\nSee that it says \"BUILD SUCCESS\" near the end.\n\nBy default, the integration tests run against an OpenSearch server.\nTo run them against an Elasticsearch server use\n\n```shell\nSEARCH_ENGINE_DOCKERFILE=\"docker/elasticsearch8/Dockerfile\" mvn install\n```\n\nor run [GitHub Action elasticsearch.yml](.github/workflows/elasticsearch.yml).\n\nThe GitHub Action automatically runs whenever a commit is pushed to the master branch.\n\n## Running it\n\n### Using Docker Compose (Recommended)\n\nThe recommended way to run the module locally is using Docker Compose. This provides a complete development environment with all dependencies.\n\n```shell\n# Build the module JAR\nmvn clean package -DskipTests\n\n# Start all services (infrastructure + module)\ndocker compose -f docker/app-docker-compose.yml up -d\n\n# View logs\ndocker compose -f docker/app-docker-compose.yml logs -f mod-search\n```\n\nFor detailed Docker Compose documentation, see [docker/README.md](docker/README.md).\n\n### Local Development with IntelliJ IDEA\n\nFor local development, you can run the application directly from IntelliJ IDEA with the `dev` profile. Spring Boot will automatically start the required infrastructure services (PostgreSQL, Kafka, OpenSearch) using Docker Compose.\n\n1. Open the project in IntelliJ IDEA\n2. Run the main application class with the `dev` profile active\n3. Spring Boot will automatically start infrastructure containers from `docker/infra-docker-compose.yml`\n\n### Manually Running the Module\n\nRun the module locally on the default listening port (8081) with infrastructure services:\n\n```shell\n# Start infrastructure services\ndocker compose -f docker/infra-docker-compose.yml up -d\n\n# Run the module\nKAFKA_HOST=localhost KAFKA_PORT=29092 \\\nDB_HOST=localhost DB_PORT=5432 DB_DATABASE=okapi_modules DB_USERNAME=folio_admin DB_PASSWORD=folio_admin \\\nELASTICSEARCH_URL=http://localhost:9200 \\\njava -Dserver.port=8081 -jar target/mod-search-*.jar\n```\n\n## Docker\n\n### Building the Docker Image\n\nBuild the docker container with:\n\n```shell\nmvn clean package -DskipTests\ndocker build -t mod-search .\n```\n\n### Running with Docker Compose\n\nThe project includes a comprehensive Docker Compose setup with two main configurations:\n\n1. **Infrastructure only** (`infra-docker-compose.yml`) - PostgreSQL, OpenSearch, Kafka, and supporting services\n2. **Full stack** (`app-docker-compose.yml`) - Infrastructure + mod-search module with scalable instances\n\n```shell\n# Run infrastructure only (for local development)\ndocker compose -f docker/infra-docker-compose.yml up -d\n\n# Run full stack with 2 module instances\ndocker compose -f docker/app-docker-compose.yml up -d\n\n# Scale module instances\ndocker compose -f docker/app-docker-compose.yml up -d --scale mod-search=3\n```\n\nSee [docker/README.md](docker/README.md) for detailed documentation on:\n- Configuration options via `.env` file\n- Multiple development workflows\n- Service descriptions and ports\n- Troubleshooting guide\n- Best practices\n\n## Multi-language search support\n\nEach tenant is allowed to pick up to **5** languages from pre-installed list for multi-language indexes (e.g. title,\ncontributors, etc.).\nThis can be done via following API (`languageAnalyzer` field is optional):\n`POST /search/config/languages`\n\n```json\n{\n  \"code\": \"eng\",\n  \"languageAnalyzer\": \"english\"\n}\n```\n\nThe `code` here is an ISO-639-2/B three-letter code. Here is the list of pre-installed languages analyzers:\n\n- ara\n- ger\n- eng\n- spa\n- fre\n- heb\n- ita\n- jpn\n- kor (default analyzer: seunjeon_analyzer, alternative for k8s and on-premise deployment - nori)\n- rus\n- swe\n- chi\n\n### Adding new languages via REST\n\nIt is allowed to add new languages via rest endpoint `/search/config/languages`.\n**Please note, when you add a new language, a whole reindex is required in order to\napply new configuration**.\n\n### Defining initial languages via ENV variable\n\nIt is possible to define initial languages via `INITIAL_LANGUAGES` env variable.\nThese languages will be added on tenant init and applied to index. Example usage:\n`INITIAL_LANGUAGES=eng,fre,kor,chi,spa`. If the variable is not defined, only\n`eng` code is added.\n\n## Deploying the module\n\n### Configuring Elasticsearch\n\n#### Configuring on-premise Elasticsearch instance\n\nIt is required to install some required plugins for your search engine instance, here is the list:\n\n* analysis-icu\n* analysis-kuromoji\n* analysis-smartcn\n* analysis-nori\n* analysis-phonetic\n\nYou can find sample Dockerfile in [docker/opensearch/Dockerfile] or install plugins manually:\n\n```shell\n${ES_HOME}/bin/opensearch-plugin install --batch \\\n  analysis-icu \\\n  analysis-kuromoji \\\n  analysis-smartcn \\\n  analysis-nori \\\n  analysis-phonetic\n```\n\nSee also [Install OpenSearch/Docker Image](https://opensearch.org/docs/latest/opensearch/install/docker/).\n\nThere is an alternative Elasticsearch image from\nBitnami - [bitnami/elasticsearch](https://hub.docker.com/r/bitnami/elasticsearch),\nthat does not require extending dockerfile but has an env variable `ELASTICSEARCH_PLUGINS` to specify plugins to\ninstall.\n\nFor production installations it is strongly recommended enabling security for instance and set-up user/password. The\nuser\nmust have at least following permissions:\n\n* Create/delete/update index and mappings for it.\n* Create/update/delete documents in index.\n\n#### Recommended production set-up\n\nThe data nodes OpenSearch configuration completely depends on the data.\nIf there are 7 mln of instances the configuration with 2 nodes with 8Gb RAM and 500 Gb disk (AWS m5.large) works well.\nThe nodes were both master and data node. We performed performance tests for this configuration, and it showed good\nresults.\nWe would recommend to performing additional performance testing (try to reindex and search with different\nconfigurations)\nwith different type of nodes, and see what configuration is sufficient for what data volume.\n\nAlso, for fault tolerance OpenSearch requires dedicated master nodes (not to have quorum problem which is called split\nbrain)\nwith less powerful configuration (\nsee [High availability](https://www.elastic.co/guide/en/cloud-enterprise/current/ece-ha.html)\nand [Cross-cluster replication](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/replication.html)).\n\n### Environment variables\n\n| Name                                               | Default value                                        | Description                                                                                                                                                                           |\n|:---------------------------------------------------|:-----------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| DB_HOST                                            | postgres                                             | Postgres hostname                                                                                                                                                                     |\n| DB_PORT                                            | 5432                                                 | Postgres port                                                                                                                                                                         |\n| DB_USERNAME                                        | postgres                                             | Postgres username                                                                                                                                                                     |\n| DB_PASSWORD                                        | postgres                                             | Postgres username password                                                                                                                                                            |\n| DB_DATABASE                                        | okapi_modules                                        | Postgres database name                                                                                                                                                                |\n| ELASTICSEARCH_URL                                  | http://elasticsearch:9200                            | Elasticsearch URL                                                                                                                                                                     |\n| ELASTICSEARCH_USERNAME                             | -                                                    | Elasticsearch username (not required for dev envs)                                                                                                                                    |\n| ELASTICSEARCH_PASSWORD                             | -                                                    | Elasticsearch password (not required for dev envs)                                                                                                                                    |\n| ELASTICSEARCH_COMPRESSION_ENABLED                  | true                                                 | Specify if Elasticsearch request/response compression enabled                                                                                                                         |\n| ELASTICSEARCH_SERVER                               | false                                                | Specify whether it is Elasticsearch(true) or Opensearch(false)                                                                                                                        |\n| KAFKA_HOST                                         | kafka                                                | Kafka broker hostname                                                                                                                                                                 |\n| KAFKA_PORT                                         | 9092                                                 | Kafka broker port                                                                                                                                                                     |\n| KAFKA_SECURITY_PROTOCOL                            | PLAINTEXT                                            | Kafka security protocol used to communicate with brokers (SSL or PLAINTEXT)                                                                                                           |\n| KAFKA_SSL_KEYSTORE_LOCATION                        | -                                                    | The location of the Kafka key store file. This is optional for client and can be used for two-way authentication for client.                                                          |\n| KAFKA_SSL_KEYSTORE_PASSWORD                        | -                                                    | The store password for the Kafka key store file. This is optional for client and only needed if 'ssl.keystore.location' is configured.                                                |\n| KAFKA_SSL_TRUSTSTORE_LOCATION                      | -                                                    | The location of the Kafka trust store file.                                                                                                                                           |\n| KAFKA_SSL_TRUSTSTORE_PASSWORD                      | -                                                    | The password for the Kafka trust store file. If a password is not set, trust store file configured will still be used, but integrity checking is disabled.                            |\n| KAFKA_EVENTS_CONSUMER_PATTERN                      | (${folio.environment}\\.\\)(.*\\.)inventory\\.(instance\\ | holdings-record\\                                                                                                                                                                      |item\\|bound-with) | Custom subscription pattern for Kafka consumers.                                                                                                                                      |\n| KAFKA_EVENTS_CONCURRENCY                           | 2                                                    | Custom number of kafka concurrent threads for message consuming.                                                                                                                      |\n| KAFKA_AUTHORITIES_CONSUMER_PATTERN                 | (${folio.environment}\\.)(.*\\.)authorities\\.authority | Custom subscription pattern for Kafka authority message consumers.                                                                                                                    |\n| KAFKA_AUTHORITIES_CONCURRENCY                      | 1                                                    | Custom number of kafka concurrent threads for authority message consuming.                                                                                                            |\n| KAFKA_LOCATION_CONCURRENCY                         | 1                                                    | Custom number of kafka concurrent threads for inventory.location, inventory.campus, inventory.institution and inventory.library message consuming.                                    |\n| KAFKA_LINKED_DATA_CONCURRENCY                      | 1                                                    | Custom number of kafka concurrent threads for linked data message consuming.                                                                                                          |\n| KAFKA_REINDEX_RANGE_INDEX_CONCURRENCY              | 1                                                    | Custom number of kafka concurrent threads for `search.reindex.range-index` message consuming.                                                                                         |\n| KAFKA_REINDEX_RANGE_INDEX_TOPIC_PARTITIONS         | 16                                                   | Amount of partitions for `search.reindex.range-index` topic.                                                                                                                          |\n| KAFKA_REINDEX_RANGE_INDEX_TOPIC_REPLICATION_FACTOR | -                                                    | Replication factor for `search.reindex.range-index` topic.                                                                                                                            |\n| KAFKA_REINDEX_RECORDS_CONCURRENCY                  | 2                                                    | Custom number of kafka concurrent threads for `inventory.reindex-records` message consuming.                                                                                          |\n| KAFKA_CONSUMER_MAX_POLL_RECORDS                    | 200                                                  | Maximum number of records returned in a single call to poll().                                                                                                                        |\n| KAFKA_RETRY_INTERVAL_MS                            | 2000                                                 | Specifies time to wait before reattempting query.                                                                                                                                     |\n| KAFKA_RETRY_DELIVERY_ATTEMPTS                      | 6                                                    | Specifies how many queries attempt to perform after the first one failed.                                                                                                             |\n| INDEXING_DATA_FORMAT                               | smile                                                | Format for passing data to elasticsearch (json/smile)                                                                                                                                 |\n| INITIAL_LANGUAGES                                  | eng                                                  | Comma separated list of languages for multilang fields see [Multi-lang search support](#multi-language-search-support)                                                                |\n| MAX_SUPPORTED_LANGUAGES                            | 5                                                    | Provides the maximum number of supported languages                                                                                                                                    |\n| SYSTEM_USER_USERNAME                               | mod-search                                           | Username for `mod-search` system user                                                                                                                                                 |\n| SYSTEM_USER_PASSWORD                               | -                                                    | Password for `mod-search` system user (not required for dev envs)                                                                                                                     |\n| OKAPI_URL                                          | -                                                    | OKAPI URL used to login system user, required                                                                                                                                         |\n| ENV                                                | folio                                                | The logical name of the deployment, must be unique across all environments using the same shared Kafka/Elasticsearch clusters, `a-z (any case)`, `0-9`, `-`, `_` symbols only allowed |\n| SEARCH_BY_ALL_FIELDS_ENABLED                       | false                                                | Specifies if globally search by all field values must be enabled or not (tenant can override this setting)                                                                            |\n| BROWSE_SUBJECTS_ENABLED                            | true                                                 | Specifies if globally browse instance subject feature is enabled                                                                                                                      |\n| BROWSE_CONTRIBUTORS_ENABLED                        | true                                                 | Specifies if globally browse instance contributor feature is enabled                                                                                                                  |\n| BROWSE_CLASSIFICATIONS_ENABLED                     | true                                                 | Specifies if globally browse instance classification feature is enabled                                                                                                               |\n| BROWSE_CALL_NUMBERS_ENABLED                        | true                                                 | Specifies if globally browse instance call-number feature is enabled                                                                                                                  |\n| SCROLL_QUERY_SIZE                                  | 1000                                                 | The number of records to be loaded by each scroll query. 10000 is a max value                                                                                                         |\n| STREAM_ID_RETRY_INTERVAL_MS                        | 1000                                                 | Specifies time to wait before reattempting query.                                                                                                                                     |\n| STREAM_ID_RETRY_ATTEMPTS                           | 3                                                    | Specifies how many queries attempt to perform after the first one failed.                                                                                                             |\n| STREAM_ID_CORE_POOL_SIZE                           | 2                                                    | The number of threads to keep in the pool, even if they are idle.                                                                                                                     |\n| STREAM_ID_MAX_POOL_SIZE                            | 2                                                    | The maximum number of threads to allow in the pool.                                                                                                                                   |\n| STREAM_ID_QUEUE_CAPACITY                           | 500                                                  | The capacity of the queue.                                                                                                                                                            |\n| STREAM_ID_JOB_EXPIRATION_DAYS                      | 7                                                    | Number of days after which the stream id job will be considered expired and cleaned up.                                                                                               |\n| SEARCH_QUERY_TIMEOUT                               | 25s                                                  | The maximum time to wait for search query response                                                                                                                                    |\n| MAX_BROWSE_REQUEST_OFFSET                          | 500                                                  | The maximum elasticsearch query offset for additional requests on browse around                                                                                                       |\n| SYSTEM_USER_ENABLED                                | true                                                 | Defines if system user must be created at service tenant initialization or used for egress service requests                                                                           |\n| REINDEX_LOCATION_BATCH_SIZE                        | 1000                                                 | Defines number of locations to retrieve per inventory http request on locations reindex process                                                                                       |\n| REINDEX_MERGE_RANGE_SIZE                           | 500                                                  | The range size that represents the number of merge entities to process during the Merge process of reindex                                                                            |\n| REINDEX_UPLOAD_RANGE_SIZE                          | 1000                                                 | The range size that represents the number of upload entities to process during the Upload process of reindex                                                                          |\n| REINDEX_UPLOAD_RANGE_LEVEL                         | 3                                                    | The level of deepness of upload range generator affecting the number of ranges to be generated                                                                                        |\n| REINDEX_MERGE_RANGE_PUBLISHER_CORE_POOL_SIZE       | 3                                                    | The number of threads for publishing the merge ranges to keep in the pool, even if they are idle.                                                                                     |\n| REINDEX_MERGE_RANGE_PUBLISHER_MAX_POOL_SIZE        | 6                                                    | The maximum number of threads for publishing the merge ranges to allow in the pool.                                                                                                   |\n| REINDEX_MERGE_RANGE_PUBLISHER_RETRY_INTERVAL_MS    | 1000                                                 | The retry interval in ms for reindex merge range request publishing.                                                                                                                  |\n| REINDEX_MERGE_RANGE_PUBLISHER_RETRY_ATTEMPTS       | 5                                                    | The maximum number of retries for reindex merge range request publishing.                                                                                                             |\n| MAX_SEARCH_BATCH_REQUEST_IDS_COUNT                 | 20000                                                | Defines maximum batch request IDs count for searching consolidated items/holdings in consortium                                                                                       |\n| INSTANCE_CHILDREN_INDEX_ENABLED                    | true                                                 | Defines if module should process subjects/contributors/classifications/call-numbers in a background                                                                                   |\n| INSTANCE_CHILDREN_INDEX_DELAY_MS                   | 60000                                                | Defines the delay for scheduler that indexes subjects/contributors/classifications/call-numbers in a background                                                                       |\n| SUB_RESOURCE_BATCH_SIZE                            | 100                                                  | Defines number of sub-resources to process at a time during background indexing                                                                                                       |\n| STALE_LOCK_THRESHOLD_MS                            | 600000                                               | Threshold to consider a sub-resource lock as stale and eligible for release                                                                                                           |\n\nThe module uses system user to communicate with other modules from Kafka consumers.\nFor production deployments you MUST specify the password for this system user via env variable:\n`SYSTEM_USER_PASSWORD=\u003cpassword\u003e`.\n\n### Configuring spring-boot\n\nSpring boot properties can be overridden using the specified environment variables, if it is not it can be done using\none of the following approaches (see also the\ndocumentation [Spring Boot Externalized Configuration](https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html)):\n\n1. Using the environment variable `SPRING_APPLICATION_JSON` (\n   example: `SPRING_APPLICATION_JSON='{\"foo\":{\"bar\":\"spam\"}}'`)\n2. Using the system variables within the `JAVA_OPTIONS` (\n   example: `JAVA_OPTIONS=-Xmx400m -Dlogging.level.org.folio.search=debug`)\n\n### Configuring connection to elasticsearch\n\nIn order to configure connection to OpenSearch or Elasticsearch you have to provide following env variables:\n\n* `ELASTICSEARCH_URL` - URL to OpenSearch or Elasticsearch master node (e.g. http(s)://elasticsearch:9200);\n* `ELASTICSEARCH_USERNAME` - username of the user to connect to OpenSearch or Elasticsearch;\n* `ELASTICSEARCH_PASSWORD` - password for the user (see\n  [OpenSearch Security configuration](https://opensearch.org/docs/latest/security-plugin/configuration/index/) or\n  [Secure the Elastic Stack](https://www.elastic.co/guide/en/elasticsearch/reference/current/secure-cluster.html)\n  for details).\n\n### Tenant attributes\n\nIt is possible to define specific tenant parameters during module's initialization for particular tenant.\n\n| Tenant parameter | Default value | Description                                                                       |\n|:-----------------|:-------------:|:----------------------------------------------------------------------------------|\n| runReindex       |     false     | Start reindex procedure automatically after module will be enabled for the tenant |\n| centralTenantId  |     null      | Central tenant Id when module is in consortia mode                                |\n\n## Data Indexing\n\n### Recreating Elasticsearch index\n\nSometimes we need to recreate OpenSearch or Elasticsearch index, for example when a breaking change introduced to index\nstructure (mapping). It can be fixed by running reindex request:\n\n```http\nPOST [OKAPI_URL]/search/index/inventory/reindex\n\nx-okapi-tenant: [tenant]\nx-okapi-token: [JWT_TOKEN]\n\n{\n  \"recreateIndex\": true,\n  \"resourceName\": \"authority\",\n  \"indexSettings\": {\n    \"numberOfShards\": 2,\n    \"numberOfReplicas\": 4,\n    \"refreshInterval\": 1\n  }\n}\n```\n\n* `resourceName` parameter is required. Possible values: `authority`, `location`,\n  `linked-data-instance`, `linked-data-work`, `linked-data-hub`. Please note that `location` reindex is synchronous.\n  Refer to [Indexing of Instance Records](#indexing-of-instance-records) section for reindexing of instances\n* `recreateIndex` parameter is optional and equal to `false` by default. If it is equal to `true` then mod-search\n  will drop existing indices for tenant and resource, creating them again. Executing request with this parameter\n  equal to `true` in query will erase all the tenant data in mod-search.\n* `indexSettings` parameter is optional and defines the following Elasticsearch/Opensearch index settings:\n  - `numberOfShards` - the number (between 1 and 100) of primary shards for the index\n  - `numberOfReplicas` - the number of replicas (between 0 and 100) each primary shard has\n  - `refreshInterval` - the refresh interval reflecting how often to make new changes to the index visible to search (seconds). `-1` disables refresh.\n* Please note that for `linked-data-instance`, `linked-data-work` and `linked-data-hub` resources the endpoint is used only for index recreation\n  purpose and actual reindex operation is triggered through mod-linked-data.\n\n### Updating index settings\n\nElasticsearch/Opensearch index settings can be updated using the following request:\n\n```http\nPUT [OKAPI_URL]/search/index/settings\n\nx-okapi-tenant: [tenant]\nx-okapi-token: [JWT_TOKEN]\n\n{\n  \"resourceName\": \"authority\",\n  \"indexSettings\": {\n    \"numberOfReplicas\": 4,\n    \"refreshInterval\": 60\n  }\n}\n```\n\n* `resourceName` parameter is required. Possible values: `instance`, `authority`, `location`, `linked-data-instance`, `linked-data-work`, `linked-data-hub`.\n* `indexSettings` parameter is optional and defines the following Elasticsearch/Opensearch index settings:\n  - `numberOfReplicas` - the number of replicas (between 0 and 100) each primary shard has\n  - `refreshInterval` - the refresh interval reflecting how often to make new changes to the index visible to search (seconds). `-1` disables refresh.\n\nIndex settings can also be specified during the running of reindex process which is described in [Recreating Elasticsearch index](#recreating-elasticsearch-index)\nand in [Indexing of Instance Records](#indexing-of-instance-records) sections.\n\n### Monitoring reindex process\n\nThere is no end-to-end monitoring implemented yet, however it is possible to monitor it partially. In order to check\nhow many records published to Kafka topic use inventory API:\n\n```http\nGET [OKAPI_URL]/authority-storage/reindex/[reindex job id]\n```\n\n_reindex job id_ - id returned by `/search/index/inventory/reindex` endpoint.\n\nIn order to estimate total records that actually added to the index, you can send a \"match all\" search query and check\n`totalRecords`, e.g. `GET /search/authorities?query=id=\"*\"`. Alternatively you can query Elasticsearch directly,\nsee [ES search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html#query-dsl-match-all-query).\n\n## Indexing of Instance Records\n\nThe section below describes the data indexing for ```instance```, ```subject```, ```contribution``` and ```classification``` resource types.\nSince ```subject```, ```contribution``` and ```classification``` are derived or child records of an Instance, in short, we are referring to\nindexing of these and ```instance``` as _Indexing of Instances_ (or _Instances Indexing_) and resources as Instance resources.\n\nThis is an improved and recommended version of instances indexing than that which is achieved with\n```POST [OKAPI_URL]/search/index/inventory/reindex``` and documented in [Data Indexing](#data-indexing) section\n\nThe whole indexing procedure consist of two steps:\n1. Merge - building the necessary data model and collection of data in accordance with the built model\n2. Upload - querying the data and adding them into OpenSearch index\n\nMerge step can be considered as Data Aggregation or Data Reloading. We need to run this step when there is a breaking change introduced to index structure (mapping).\nNormally, we run Instances indexing with this step rarely, as introducing the breaking changes does not happen that frequently. The step aggregates all instances data\navailable for the tenant into specific data models and keeps them there. For Create/Update/Delete operations performed on specific Instances mod-search will\nupdate or sync the aggregated data of those specific Instances, so that the aggregated data is always actual and represents the latest state of an instance resources.\n\nUpload step queries the aggregated data for the specific Instance resources type and then runs the indexing by populating the data into resource's OpenSearch index.\n\nWe can execute both Merge and Upload steps with so-called _full reindex_ API:\n```http\nPOST /search/index/instance-records/reindex/full\n\nx-okapi-tenant: [tenant]\nx-okapi-token: [JWT_TOKEN]\n\n{\n  \"indexSettings\": {\n    \"numberOfShards\": 2,\n    \"numberOfReplicas\": 4,\n    \"refreshInterval\": 1\n  }\n}\n\n```\n* `indexSettings` parameter is optional and defines the following Elasticsearch/Opensearch index settings:\n  - `numberOfShards` - the number (between 1 and 100) of primary shards for the index\n  - `numberOfReplicas` - the number of replicas (between 0 and 100) each primary shard has\n  - `refreshInterval` - the refresh interval reflecting how often to make new changes to the index visible to search (seconds). `-1` disables refresh.\n\nIt runs the async process which performs both steps described above.\n\nIf Instances Indexing was performed in the past, we have aggregated data of instances stored in our models, and changes we made do not require\nto perform mapping between the inventory Instance resources and OpenSearch indices then running the Merge Step in this and subsequent times is not\nnecessary, and we can run only Upload step. In order to do this we can call the following async API:\n\n```http\nPOST /search/index/instance-records/reindex/upload\n\nx-okapi-tenant: [tenant]\nx-okapi-token: [JWT_TOKEN]\n\n{\n  \"entityTypes\": [\"instance\", \"subject\", \"contributor\", \"classification\", \"call-number\"]\n}\n```\n\nWe can call the above API as _upload reindex_ API as it runs only Upload step. So, the assumption for running _upload reindex_ is that Merge step was run before with _full reindex_ API.\nIf it is not the case or if our changes require to run the Merge step which means there are breaking changes on the mapping between the inventory Instance resources and OpenSearch indices\nthen _full reindex_ API.\n\nWe can specify one or many resource types in ```entityTypes``` array depending on our needs and if more than one resource type is given then upload step will run for each one of the\nspecified resources.\n\nIn order to monitor the async processes initiated by the above two APIs we can execute the endpoint:\n```http\nGET /search/index/instance-records/reindex/status\n```\n\nand it returns a response showing the status details for the latest run operations, merge and upload alike, which may look like the following:\n```json\n[\n  {\n    \"entityType\": \"holding\",\n    \"status\": \"MERGE_COMPLETED\",\n    \"totalMergeRanges\": 5,\n    \"processedMergeRanges\": 5,\n    \"totalUploadRanges\": 0,\n    \"processedUploadRanges\": 0,\n    \"startTimeMerge\": \"2024-04-01T00:38:34.15755006Z\",\n    \"endTimeMerge\": \"2024-04-01T00:38:35.15755006Z\"\n  },\n  {\n    \"entityType\": \"item\",\n    \"status\": \"MERGE_COMPLETED\",\n    \"totalMergeRanges\": 3,\n    \"processedMergeRanges\": 3,\n    \"totalUploadRanges\": 0,\n    \"processedUploadRanges\": 0,\n    \"startTimeMerge\": \"2024-04-01T00:37:34.15755006Z\",\n    \"endTimeMerge\": \"2024-04-01T00:37:35.15755006Z\"\n  },\n  {\n    \"entityType\": \"instance\",\n    \"status\": \"UPLOAD_COMPLETED\",\n    \"totalMergeRanges\": 3,\n    \"processedMergeRanges\": 3,\n    \"totalUploadRanges\": 2,\n    \"processedUploadRanges\": 2,\n    \"startTimeMerge\": \"2024-04-01T00:37:34.15755006Z\",\n    \"endTimeMerge\": \"2024-04-01T00:37:35.15755006Z\",\n    \"startTimeUpload\": \"2024-04-01T00:37:36.15755006Z\",\n    \"endTimeUpload\": \"2024-04-01T00:37:37.15755006Z\"\n  },\n  {\n    \"entityType\": \"subject\",\n    \"status\": \"UPLOAD_COMPLETED\",\n    \"totalMergeRanges\": 0,\n    \"processedMergeRanges\": 0,\n    \"totalUploadRanges\": 2,\n    \"processedUploadRanges\": 2,\n    \"startTimeUpload\": \"2024-04-01T01:37:36.15755006Z\",\n    \"endTimeUpload\": \"2024-04-01T01:37:37.15755006Z\"\n  }\n]\n```\n\nWhen ```entityType``` has value of ```item``` or ```holding``` then we have status details of Merge step\nand when ```entityType``` has value of ```subject```, ```contributor``` or ```classification``` then we have status details of Upload step.\nOnly for entity type of ```instance``` we can have statuses of both Merge and Upload steps.\n\n```status``` response field can have values of ```\"MERGE_IN_PROGRESS\"```, ```\"MERGE_COMPLETED\"``` or ```\"MERGE_FAILED\"``` for entity types\nrepresenting Merge step and values of ```\"UPLOAD_IN_PROGRESS\"```, ```\"UPLOAD_COMPLETED\"``` or ```\"UPLOAD_FAILED\"``` for the entities of Upload step.\n\n## API\n\n### CQL support\n\nWe use CQL query for search queries,\nsee [documentation](https://github.com/folio-org/raml-module-builder#cql-contextual-query-language)\nfor more details.\n\nIn mod-search there are two main types of searchable fields:\n\n1. _Full text_ capable fields (aka. multi-lang fields) - analyzed and preprocessed fields;\n2. _Term_ fields (keywords, bool, date fields, etc.) - non-analyzed fields.\n\n#### CQL query operators\n\nDepending on field type, CQL operators will be handled in different ways or not supported at all.\nHere is table of supported operators.\n\n| Operator   | Full text usage                | Term field usage              | Description                                                                                                                                        |\n|:-----------|:-------------------------------|:------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|\n| `all`      | `title` `all` `\"semantic web\"` | N/A                           | Matches a resource that has both `semantic` and `web` in the `title` field                                                                         |\n| `any`      | `title` `any` `\"semantic web\"` | N/A                           | Matches a resource that has either of/both `semantic` or `web` in the `title` field                                                                |\n| `=`        | `title = \"semantic web\"`       | `hrid = \"hr10\"`               | Has the same effect as `all` for FT fields and is the same as `==` for term fields                                                                 |\n| `==`       | `title == \"semantic web\"`      | `hrid == \"hr10\"`              | Phrase match for FT fields (i.e. matches resources that contains both `semantic` and `web` exactly in the same order), exact match for term fields |\n| `\u003c\u003e`       | `title \u003c\u003e \"semantic web\"`      | `hrid \u003c\u003e \"hr10\"`              | Matches resources that are not equal to a term                                                                                                     |\n| `\u003c`, `\u003e`   | N/A                            | `createdDate \u003e \"2020-12-12\"`  | Matches resources that has the property greater/less than the limit                                                                                |\n| `\u003c=`, `\u003e=` | N/A                            | `createdDate \u003c= \"2020-12-12\"` | Matches resources that has the property greater or eq/less or eq than the limit                                                                    |\n| `*`        | `title=\"mode* europe*\"`        | `hrid = \"hr10*\"`              | Allow to search by wildcard, _**NOT recommended to use for FT fields because has low performance, use full-text capabilities instead**_            |\n\n#### CQL query modifiers\n\nCQL operators could have modifiers that change search behaviour\n\n| Operator | Modifier | Usage                            | Description                      |\n|:---------|:---------|:---------------------------------|:---------------------------------|\n| `==`     | `string` | `title ==/string \"semantic web\"` | Exact match for full text fields |\n\n#### Consortium support\n\nConsortium feature is defined automatically at runtime by calling /user-tenants endpoint.\nConsortium feature on module enable is defined by 'centralTenantId' tenant parameter. Example:\n\n```json\n{\n  \"module_to\": \"mod-sample-1.3.1\",\n  \"parameters\": [\n    {\n      \"key\": \"centralTenantId\",\n      \"value\": \"centralTenant\"\n    },\n    {\n      \"key\": \"loadReference\",\n      \"value\": true\n    }\n  ]\n}\n```\n\n### Search API\n\n| METHOD | URL                             | DESCRIPTION                                                                          |\n|:-------|:--------------------------------|:-------------------------------------------------------------------------------------|\n| GET    | `/search/instances`             | Search by instances and to this instance items and holding-records                   |\n| GET    | `/search/authorities`           | Search by authority records                                                          |\n| GET    | `/search/linked-data/instances` | Search linked data graph instance resource descriptions                              |\n| GET    | `/search/linked-data/works`     | Search linked data graph work resource descriptions                                  |\n| GET    | `/search/linked-data/hubs`      | Search linked data graph hub resource descriptions                                   |\n| GET    | `/search/{recordType}/facets`   | Get facets where recordType could be: instances, authorities, contributors, subjects |\n\n#### Searching and filtering\n\nThe main endpoint that provides search capabilities is `GET /search/instances`. It consumes following\nrequest parameters:\n\n| Name      | Required              | Default value | Description                                                                        |\n|:----------|:----------------------|:--------------|:-----------------------------------------------------------------------------------|\n| query     | Yes                   | -             | A CQL query to execute                                                             |\n| limit     | No (default to 100)   | 100           | Maximum number of records to fetch                                                 |\n| offset    | No (default to 0)     | 0             | Instructs to skip first N records that matches the query                           |\n| expandAll | No (default to false) | false         | If false than only _*basic_ instance properties returned, otherwise all properties |\n\n\u003e *_Basic fields for instances search are following:_\n\u003e * _id_\n\u003e * _tenantId_\n\u003e * _shared_\n\u003e * _hrid_\n\u003e * _discoverySuppress_\n\u003e * _isBoundWith_\n\u003e * _title_\n\u003e * _contributors_\n\u003e * _identifiers_\n\u003e * _publication_\n\u003e * _dates_\n\n\u003e *_Basic fields for authorities search are following:_\n\u003e * _id_\n\u003e * _headingType_\n\u003e * _authRefType_\n\u003e * _headingRef_\n\u003e * _sourceFileId_\n\u003e * _naturalId_\n\n##### Matching all records\n\nA search matching all records in the target index can be executed with a `cql.allRecords=1` (CQL standard, the fastest\noption)\nor a `id=*` (slower option, check all documents in index) query. They can be used alone or as part of a more complex\nquery.\nExamples:\n\n- `cql.allRecords=1 NOT contributors=Smith sortBy title/sort.ascending` matches all records where contributors name does\n  not contain `Smith` as a word.\n- `id=* NOT contributors=Smith sortBy title/sort.ascending` matches all records where contributors name does not\n  contain `Smith` as a word.\n\n##### Matching undefined or empty values\n\nA relation does not match if the value on the left-hand side is undefined.\nA negation (using NOT) of a relation matches if the value on the left-hand side is not defined or\nif it is defined but doesn't match.\n\n- `name=\"\"` matches all records where name is defined.\n- `cql.allRecords=1 NOT name=\"\"` matches all records where name is not defined.\n- `name==\"\"` matches all records where name is defined and empty.\n- `cql.allRecords=1 NOT name==\"\"` matches all records where name is defined and not empty or where name is not defined.\n- `name=\"\" NOT name==\"\"` matches all records where name is defined and not empty.\n- `languages == \"[]\"` for matching records where lang is defined and an empty array\n\n##### Search by all field values\n\nSearch by all feature is optional and disabled by default. However, it can be enabled for tenant using\nfollowing HTTP request:\n\n`POST /search/config/features`\n\n```json\n{\n  \"feature\": \"search.all.fields\",\n  \"enabled\": true\n}\n```\n\nAlso, search by all fields can be enabled globally by passing to mod-search service following ENV variable:\n\n```\nSEARCH_BY_ALL_FIELDS_ENABLED=true\n```\n\nBy default, indexing processors for fields `cql.allInstance`, `cql.allItems`, `cql.allHoldings` are disabled and\ndoes not produce any values, so the following search options will return an empty result.\n\n| Option             |       Type        | Example                          | Description                                                                       |\n|:-------------------|:-----------------:|:---------------------------------|:----------------------------------------------------------------------------------|\n| `cql.all`          | full-text or term | `cql.all all \"web semantic\"`     | Matches instances that have given text in instance, item and holding field values |\n| `cql.allItems`     | full-text or term | `cql.allItems all \"book\"`        | Matches instances that have given text in item field values                       |\n| `cql.allHoldings`  | full-text or term | `cql.allHoldings all \"it001\"`    | Matches instances that have given text in holding field values                    |\n| `cql.allInstances` | full-text or term | `cql.allInstances any \"1234567\"` | Matches instances that have given text in instance field values                   |\n\n##### Instance search options\n\n| Option                                 |    Type     | Example                                                                  | Description                                                                                                                                       |\n|:---------------------------------------|:-----------:|:-------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------|\n| `keyword`                              |  full-text  | `keyword all \"web semantic\"`                                             | An alias for: `title`, `alternativeTitles`, `indexTitle`, `series`, `contributors.name`                                                           |\n| `id`                                   |    term     | `id==\"1234567\"`                                                          | Matches instance with the id                                                                                                                      |\n| `hrid`                                 |    term     | `hrid==\"hr1*0\"`                                                          | Matches instances with given HRID                                                                                                                 |\n| `source`                               |    term     | `source==\"MARC\"`                                                         | Matches instances with given source (FOLIO/MARC)                                                                                                  |\n| `title`                                |  full-text  | `title all \"semantic web\"`                                               | An alias for: `title`, `alternativeTitles`, `indexTitle`, `series`                                                                                |\n| `alternativeTitles.alternativeTitle`   |  full-text  | `alternativeTitles.alternativeTitle all \"semantic web\"`                  | Matches instances with the given alternative title                                                                                                |\n| `uniformTitle`                         |  full-text  | `uniformTitle all \"semantic web\"`                                        | Matches instances with the given uniform title                                                                                                    |\n| `indexTitle`                           |  full-text  | `indexTitle all \"semantic web\"`                                          | Matches instances with the given index title                                                                                                      |\n| `series`                               |  full-text  | `series all \"series\"`                                                    | Matches instance with given series value                                                                                                          |\n| `identifiers.value`                    |    term     | `identifiers.value = \"1023*\"`                                            | Matches instances with the given identifier value                                                                                                 |\n| `identifiers.identifierTypeId`         |    term     | `identifiers.identifierTypeId==\"123\" identifiers.value = \"1023*\"`        | Matches instances that have an identifier of type `123` and ANY identifier with value `1023*`                                                     |\n| `contributors`                         |  full-text  | `contributors all \"John\"`                                                | An alias for: `contributors.name`                                                                                                                 |\n| `contributors.name`                    |  full-text  | `contributors.name all \"John\"`                                           | Matches instances that have a `John` contributor                                                                                                  |\n| `contributors.contributorTypeId`       |    term     | `contributors.contributorTypeId all \"1234567\"`                           | Matches instances that have a contributor type Id `1234567`                                                                                       |\n| `contributors.contributorNameTypeId`   |    term     | `contributors.contributorNameTypeId all \"1234567\"`                       | Matches instances that have a contributor name type Id `1234567`                                                                                  |\n| `contributors.primary`                 |    term     | `contributors all \"John\" and contributors.primary==true`                 | Matches instances that have a primary `John` contributor                                                                                          |\n| `contributors.authorityId`             |    term     | `contributors.authorityId == \"81ae0f60-f2bc-450c-84c8-5a21096daed9\"`     | Matches instances that have a contributor authorityId `81ae0f60-f2bc-450c-84c8-5a21096daed9`                                                      |\n| `authorityId`                          |    term     | `authorityId == \"81ae0f60-f2bc-450c-84c8-5a21096daed9\"`                  | Matches instances that have a contributor authorityId `81ae0f60-f2bc-450c-84c8-5a21096daed9`                                                      |\n| `subjects`                             |  full-text  | `subjects all \"Chemistry\"`                                               | Matches instances that have a `Chemistry` subject                                                                                                 |\n| `instanceTypeId`                       |    term     | `instanceTypeId == \"123\"`                                                | Matches instances with the `123` type                                                                                                             |\n| `statusId`                             |    term     | `statusId == \"123\"`                                                      | Matches instances with the `123` status                                                                                                           |\n| `instanceFormatIds`                    |    term     | `instanceFormatIds == \"123\"`                                             | Matches instances with the `123` format id                                                                                                        |\n| `languages`                            |    term     | `languages == \"eng\"`                                                     | Matches instances that have `eng` language                                                                                                        |\n| `metadata.createdDate`                 |    term     | `metadata.createdDate \u003e \"2021-03-01T00:00:00.000+00:00\"`                 | Matches instances that were created after  `2020-12-12`                                                                                           |\n| `metadata.updatedDate`                 |    term     | `metadata.updatedDate \u003e \"2020-12-12\"`                                    | Matches instances that were updated after  `2020-12-12`                                                                                           |\n| `modeOfIssuanceId`                     |    term     | `modeOfIssuanceId==\"123\"`                                                | Matches instances that have `123` mode of issuance                                                                                                |\n| `natureOfContentTermIds`               |    term     | `natureOfContentTermIds==\"123\"`                                          | Matches instances that have `123` nature of content                                                                                               |\n| `publisher`                            |  full-text  | `publisher all \"Publisher of Ukraine\"`                                   | Matches instances that have `Publisher of Ukraine` publisher                                                                                      |\n| `publication.place`                    |  full-text  | `publication.place all \"Ukraine\"`                                        | Matches instances that have `Ukraine` in publication place                                                                                        |\n| `instanceTags`                         |    term     | `instanceTags==\"important\"`                                              | Matches instances that have `important` tag                                                                                                       |\n| `classifications.classificationNumber` |    term     | `classifications.classificationNumber==\"cl1\"`                            | Matches instances that have `cl1` classification number                                                                                           |\n| `classifications.classificationTypeId` |    term     | `classifications.classificationTypeId==\"123\"`                            | Matches instances that have classification type id `123`                                                                                          |\n| `electronicAccess`                     |  full-text  | `electronicAccess any \"resource\"`                                        | An alias for `electronicAccess` fields - `uri`, `linkText`, `publicNote`                                                                          |\n| `electronicAccess.uri`                 |    term     | `electronicAccess.uri=\"http://folio.org*\"`                               | Search by electronic access URI                                                                                                                   |\n| `electronicAccess.linkText`            |  full-text  | `electronicAccess.linkText=\"Folio website\"`                              | Search by electronic access link text                                                                                                             |\n| `electronicAccess.publicNote`          |  full-text  | `electronicAccess.publicNote=\"a rare book\"`                              | Search by electronic access public note                                                                                                           |\n| `electronicAccess.relationshipId`      |  full-text  | `electronicAccess.relationshipId=\"c0097d76-7ccf-4fc7-b87a-b0ec7278966f\"` | Search by electronic access relationship type ID                                                                                                  |\n| `staffSuppress`                        |    term     | `staffSuppress==true`                                                    | Matches instances that are staff suppressed                                                                                                       |\n| `discoverySuppress`                    |    term     | `discoverySuppress==true`                                                | Matches instances that are suppressed from discovery                                                                                              |\n| `publicNotes`                          |  full-text  | `publicNotes all \"public note\"`                                          | Matches instances that have a public note (i.e. `note.staffOnly` is `false`)                                                                      |\n| `administrativeNotes`                  |  full-text  | `administrativeNotes all \"librarian note\"`                               | Search by administrative notes                                                                                                                    |\n| `notes.note`                           |  full-text  | `notes.note all \"librarian note\"`                                        | Search by instance notes (include staffOnly)                                                                                                      |\n| `isbn`                                 |    term     | `isbn=\"1234*\"`                                                           | Matches instances that have an ISBN identifier with the given value                                                                               |\n| `issn`                                 |    term     | `issn=\"1234*\"`                                                           | Matches instances that have an ISSN identifier with the given value                                                                               |\n| `oclc`                                 |    term     | `oclc=\"1234*\"`                                                           | Matches instances that have an OCLC identifier with the given value                                                                               |\n| `lccn`                                 |    term     | `lccn = \"LCCN\"`                                                          | Matches instances with the given lccn                                                                                                             |\n| `canceledLccn`                         |    term     | `canceledLccn = \"LCCN-OLD\"`                                              | Matches instances with the given canceled lccn                                                                                                    |\n| `normalizedClassificationNumber`       |    term     | `normalizedClassificationNumber == \"LCCN\"`                               | Matches instances with the given classification number (normalizes case, whitespaces, special characters, supports leading and trailing wildcard) |\n| `normalizedDate1`                      |    term     | `normalizedDate1\u003e=1990`                                                  | Matches instances with the given Date1 (normalizes  alpha 'u' characters)                                                                         |\n| `classificationId`                     |    term     | `classificationId = \"c4f60d7413158e9466856f4c0250d91d312f86cf\"`          | Matches instances with the given classificationId                                                                                                 |\n\n##### Holdings search options\n\n| Option                                      |   Type    | Example                                                                            | Description                                                                                         |\n|:--------------------------------------------|:---------:|:-----------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------|\n| `holdings.id`                               |   term    | `holdings.id==\"1234567\"`                                                           | Matches instances that have a holding with the id                                                   |\n| `holdings.sourceId`                         |   term    | `holdings.sourceId==\"FOLIO\"`                                                       | Matches instances that have a holding with the source `FOLIO`                                       |\n| `holdings.holdingsTypeId`                   |   term    | `holdings.holdingsTypeId==\"1234567\"`                                               | Matches instances that have a holding with the holdings type id `1234567`                           |\n| `holdings.permanentLocationId`              |   term    | `holdings.permanentLocationId==\"123765\"`                                           | Matches instances that have holdings with given statisticalCodeId                                   |\n| `holdings.statisticalCodeIds`               |   term    | `holdings.statisticalCodeIds==\"123765\"`                                            | Matches instances that have holdings with given permanentLocationId                                 |\n| `holdings.discoverySuppress`                |   term    | `holdings.discoverySuppress==true`                                                 | Matches instances that have holdings suppressed/not suppressed from discovery                       |\n| `holdings.hrid`                             |   term    | `holdings.hrid==\"hr10*3\"`                                                          | Matches instances that have a holding with given HRID                                               |\n| `holdingsTags`                              |   term    | `holdingsTags==\"important\"`                                                        | Matches instances that have holdings with given tags                                                |\n| `holdingsFullCallNumbers`                   |   term    | `holdingsFullCallNumbers=\"cn*434\"`                                                 | Matches instances that have holdings with given call number string (prefix + call number + suffix)  |\n| `holdingsNormalizedCallNumbers`             |   term    | `holdingsNormalizedCallNumbers=\"cn434\"`                                            | Matches instances that have holdings with given call number and might not be formatted correctly    |\n| `holdings.electronicAccess`                 | full-text | `holdings.electronicAccess any \"resource\"`                                         | An alias for `electronicAccess` fields - `uri`, `linkText`, `publicNote`                            |\n| `holdings.electronicAccess.uri`             |   term    | `holdings.electronicAccess.uri=\"http://folio.org*\"`                                | Search by electronic access URI                                                                     |\n| `holdings.electronicAccess.linkText`        | full-text | `holdings.electronicAccess.linkText=\"Folio website\"`                               | Search by electronic access link text                                                               |\n| `holdings.electronicAccess.publicNote`      | full-text | `holdings.electronicAccess.publicNote=\"a rare book\"`                               | Search by electronic access public note                                                             |\n| `holdings.electronicAccess.relationshipId`  | full-text | `holdings.electronicAccess.relationshipId=\"ca11edb1-309d-4df7-ab26-95f4cbb3489f\"`  | Search by electronic access relationship type ID                                                    |\n| `holdings.administrativeNotes`              | full-text | `holdings.administrativeNotes all \"librarian note\"`                                | Search by holdings administrative notes                                                             |\n| `holdings.notes.note`                       | full-text | `holdings.notes.note all \"librarian note\"`                                         | Search by holdings notes                                                                            |\n| `holdingsTypeId`                            |   term    | `holdingsTypeId==\"123\"`                                                            | Search by holdings type id                                                                          |\n| `holdingsPublicNotes`                       | full-text | `holdingsPublicNotes all \"public note\"`                                            | Search by holdings public notes                                                                     |\n| `holdingsIdentifiers`                       |   term    | `holdingsIdentifiers == \"ho00000000006\"`                                           | Search by holdings Identifiers: `holdings.id`, `holdings.hrid`, `holdings.formerIds`                |\n| `holdings.metadata.createdDate`             |   term    | `metadata.createdDate \u003e \"2020-12-12\"`                                              | Matches instances with holdings that were created after  `2020-12-12`                               |\n| `holdings.metadata.updatedDate`             |   term    | `metadata.updatedDate \u003e \"2020-12-12\"`                                              | Matches instances with holdings that were updated after  `2020-12-12`                               |\n\n##### Item search options\n\n| Option                                                |   Type    | Example                                                                               | Description                                                                                                         |\n|:------------------------------------------------------|:---------:|:--------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------|\n| `item.id`                                             |   term    | `item.id==\"1234567\"`                                                                  | Matches instances that have an item with the id                                                                     |\n| `item.hrid`                                           |   term    | `item.hrid==\"it001\"`                                                                  | Matches instances that have an item with the HRID                                                                   |\n| `item.barcode`                                        |   term    | `item.barcode==\"10011\"`                                                               | Matches instances that have an item with the barcode                                                                |\n| `item.effectiveLocationId`                            |   term    | `item.effectiveLocationId==\"1212\"`                                                    | Matches instances that have item with the effective location                                                        |\n| `item.statisticalCodeIds`                             |   term    | `item.statisticalCodeIds==\"1212\"`                                                     | Matches instances that have item with the statistical code Id                                                       |\n| `item.status.name`                                    |   term    | `item.status.name==\"Available\"`                                                       | Matches instances that have item with given status                                                                  |\n| `item.materialTypeId`                                 |   term    | `item.materialTypeId=\"23434\"`                                                         | Matches instances that have item with given material type                                                           |\n| `item.discoverySuppress`                              |   term    | `item.discoverySuppress=true`                                                         | Matches instances that have item suppressed/not suppressed from discovery                                           |\n| `itemFullCallNumbers`                                 |   term    | `itemFullCallNumbers=\"cn*434\"`                                                        | Matches instances that have item with given call number string (prefix + call number + suffix)                      |\n| `itemNormalizedCallNumbers`                           |   term    | `itemNormalizedCallNumbers=\"cn434\"`                                                   | Matches instances that have item with given call number and might not be formatted correctly                        |\n| `itemLevelCallNumberTypeId`                           |   term    | `itemLevelCallNumberTypeId=\"81ae0f60-f2bc-450c-84c8-5a21096daed9\"`                    | Matches instances that have item with given call number type id                                                     |\n| `itemTags`                                            |   term    | `itemTags=\"important\"`                                                                | Matches instances that have item with given tag                                                                     |\n| `item.electronicAccess`                               | full-text | `item.electronicAccess any \"resource\"`                                                | An alias for `electronicAccess` fields - `uri`, `linkText`, `publicNote`                                            |\n| `item.electronicAccess.uri`                           |   term    | `item.electronicAccess.uri=\"http://folio.org*\"`                                       | Search by electronic access URI                                                                                     |\n| `item.electronicAccess.linkText`                      | full-text | `item.electronicAccess.linkText=\"Folio website\"`                                      | Search by electronic access link text                                                                               |\n| `item.electronicAccess.publicNote`                    | full-text | `item.electronicAccess.publicNote=\"a rare book\"`                                      | Search by electronic access public note                                                                             |\n| `item.electronicAccess.relationshipId`                | full-text | `item.electronicAccess.relationshipId=\"3f958bad-2847-47de-bc01-e4f53243ab1d\"`         | Search by electronic access relationship type ID                                                                    |\n| `item.administrativeNotes`                            | full-text | `item.administrativeNotes all \"librarian note\"`                                       | Search by item administrative notes                                                                                 |\n| `item.notes.note`                                     | full-text | `item.notes.note all \"librarian note\"`                                                | Search by item notes and circulation notes                                                                          |\n| `item.circulationNotes.note`                          | full-text | `item.circulationNotes.note all \"circulation note\"`                                   | Search by item circulation notes                                                                                    |\n| `itemPublicNotes`                                     | full-text | `itemPublicNotes all \"public note\"`                                                   | Search by item public notes and circulation notes                                                                   |\n| `itemIdentifiers`                                     |   term    | `itemIdentifiers all \"81ae0f60-f2bc-450c-84c8-5a21096daed9\"`                          | Search by item Identifiers: `item.id`, `item.hrid`, `item.formerIds`, `item.accessionNumber`, `item.itemIdentifier` |\n| `item.effectiveCallNumberComponents.typeId = {value}` |   term    | `item.effectiveCallNumberComponents.typeId == \"81ae0f60-f2bc-450c-84c8-5a21096daed9\"` | Search by item call-number typeId  `81ae0f60-f2bc-450c-84c8-5a21096daed9`                                           |\n| `item.metadata.createdDate`                           |   term    | `item.metadata.createdDate \u003e \"2020-12-12\"`                                            | Matches instances with item that were created after  `2020-12-12`                                                   |\n| `item.metadata.updatedDate`                           |   term    | `item.metadata.updatedDate \u003e \"2020-12-12\"`                                            | Matches instances with item that were updated after  `2020-12-12`                                                   |\n\n##### Authority search options\n\n| Option                         |   Type    | Example                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n|:-------------------------------|:---------:|:----------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `keyword`                      | full-text | `keyword all \"web semantic\"`                  | An alias for: `personalName`, `sftPersonalName`, `saftPersonalName`, `personalNameTitle`, `sftPersonalNameTitle`, `saftPersonalNameTitle`, `corporateName`, `sftCorporateName`, `saftCorporateName`, `corporateNameTitle`, `sftCorporateNameTitle`, `saftCorporateNameTitle`, `meetingName`, `sftMeetingName`, `saftMeetingName`, `meetingNameTitle`, `sftMeetingNameTitle`, `saftMeetingNameTitle`, `uniformTitle`, `sftUniformTitle`, `saftUniformTitle`, `topicalTerm`, `sftTopicalTerm`, `saftTopicalTerm`, `geographicName`, `sftGeographicName`, `saftGeographicName`, `genreTerm`, `sftGenreTerm`, `saftGenreTerm`               |\n| `id`                           |   term    | `id==\"1234567\"`                               | Matches authorities with the id                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| `headingType`                  |   term    | `headingType == \"Personal Name\"`              | Matches authorities with `Personal Name` heading type                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| `isTitleHeadingRef`            |   term    | `isTitleHeadingRef == true`                   | Matches authorities with `personalNameTitle`, `sftPersonalNameTitle`, `saftPersonalNameTitle`, `corporateNameTitle`, `sftCorporateNameTitle`, `saftCorporateNameTitle`, `meetingNameTitle`, `sftMeetingNameTitle`, `saftMeetingNameTitle`                                                                                                                                                                                                                                                                                                                                                                                               |\n| `authRefType`                  |   term    | `authRefType == \"Authorized\"`                 | Matches authorities with `Authorized` auth/ref type                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| `lccn`                         |   term    | `lccn = \"LCCN\"`                               | Matches authorities with the given lccn                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |\n| `canceledLccn`                 |   term    | `canceledLccn = \"LCCN-OLD\"`                   | Matches authorities with the given canceled lccn                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |\n| `identifiers.value`            |   term    | `identifiers.value = \"1023*\"`                 | Matches authorities with the given identifier value                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |\n| `identifiers.identifierTypeId` |   term    | `identifiers.identifierTypeId==\"123\"`         | Matches authorities that the given identifier type id                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| `metadata.createdDate`         |   term    | `metadata.createdDate \u003e \"2020-12-12\"`         | Matches authorities that were created after `2020-12-12`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `metadata.updatedDate`         |   term    | `metadata.updatedDate \u003e \"2020-12-12\"`         | Matches authorities that were updated after `2020-12-12`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `sourceFileId`                 |   term    | `sourceFileId = \"12345\"`                      | Matches authorities with `12345` source file id                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |\n| `naturalId`                    |   term    | `naturalId = \"12345\"`                         | Matches authorities with `12345` natural id                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |\n| `subjectHeadings`              | full-text | `subjectHeadings any \"z\"`                     | Matches authorities with `z` subject headings                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| `personalName`                 | full-text | `personalName any \"john\"`                     | Matches authorities with `john` personal name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| `sftPersonalName`              | full-text | `sftPersonalName any \"john\"`                  | Matches authorities with `john` sft personal name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |\n| `saftPersonalName`             | full-text | `saftPersonalName any \"john\"`                 | Matches authorities with `john` saft personal name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| `personalNameTitle`            | full-text | `personalNameTitle any \"personal title\"`      | Matches authorities with `personal title` personal name title                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| `sftPersonalNameTitle`         | full-text | `sftPersonalNameTitle any \"personal title\"`   | Matches authorities with `personal title` sft personal name title                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |\n| `saftPersonalNameTitle`        | full-text | `saftPersonalNameTitle any \"personal title\"`  | Matches authorities with `personal title` saft personal name title                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |\n| `corporateName`                | full-text | `corporateName == \"corporate name\"`           | Matches authorities with `corporate name` corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `sftCorporateName`             | full-text | `sftCorporateName == \"corporate name\"`        | Matches authorities with `corporate name` sft corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n| `saftCorporateName`            | full-text | `saftCorporateName == \"corporate name\"`       | Matches authorities with `corporate name` saft corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| `corporateNameTitle`           | full-text | `corporateNameTitle == \"corporate title\"`     | Matches authorities with `corporate title` corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |\n| `sftCorporateNameTitle`        | full-text | `sftCorporateNameTitle == \"corporate title\"`  | Matches authorities with `corporate title` sft corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |\n| `saftCorporateNameTitle`       | full-text | `saftCorporateNameTitle == \"corporate title\"` | Matches authorities with `corporate title` saft corporate name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |\n| `meetingName`                  | full-text | `meetingName == \"conferenece name\"`           | Matches authorities with `conferenece name` meeting name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| `sftMeetingName`               | full-text | `sftMeetingName == \"conferenece name\"`        | Matches authorities with `conferenece name` sft meeting name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n| `saftMeetingName`              | full-text | `saftMeetingName == \"conferenece name\"`       | Matches authorities with `conferenece name` saft meeting name                                                               ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Fmod-search","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffolio-org%2Fmod-search","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Fmod-search/lists"}