{"id":13879470,"url":"https://github.com/piktur/pg_multisearch","last_synced_at":"2025-07-16T15:32:27.381Z","repository":{"id":89877024,"uuid":"160910674","full_name":"piktur/pg_multisearch","owner":"piktur","description":"Multi-type Full Text Search plugin for PostgreSQL and ActiveRecord","archived":false,"fork":false,"pushed_at":"2019-02-11T01:07:20.000Z","size":232,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-08-07T08:12:40.503Z","etag":null,"topics":["activerecord","arel","postgres","postgresql","rails","ruby","search","searching"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piktur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-12-08T06:22:36.000Z","updated_at":"2020-06-15T17:36:16.000Z","dependencies_parsed_at":"2023-06-15T23:30:10.876Z","dependency_job_id":null,"html_url":"https://github.com/piktur/pg_multisearch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piktur%2Fpg_multisearch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piktur%2Fpg_multisearch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piktur%2Fpg_multisearch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piktur%2Fpg_multisearch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piktur","download_url":"https://codeload.github.com/piktur/pg_multisearch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226143895,"owners_count":17580245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["activerecord","arel","postgres","postgresql","rails","ruby","search","searching"],"created_at":"2024-08-06T08:02:22.099Z","updated_at":"2024-11-24T08:31:23.182Z","avatar_url":"https://github.com/piktur.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# [PgMultisearch](http://github.com/piktur/pg_multisearch)\n\n[![Build Status](https://travis-ci.com/piktur/pg_multisearch.svg?branch=master)](https://travis-ci.com/piktur/pg_multisearch)\n\nPgMultisearch provides **Full Text Search** capabilities against a global search index.\n\nInspired by and improves upon [`pg_search`'s](https://github.com/Casecommons/pg_search) [multi search](https://github.com/Casecommons/pg_search#multi-search) feature.\n\n## Install\n\n### Rails\n\n```bash\n  bin/rails g pg_multisearch:install Search \\\n  --types Organisation Product Interview Post Move Person \\\n  --use '{ \"age\": { \"column\": \"provenance\" }, \"document\": { \"index\": true } }'\n```\n\n## Configuration\n\n```ruby\n# config/initializers/pg_multisearch.rb\n\nrequire 'pg_multisearch'\n\n# Configure defaults. Defaults will be applied to each scope when missing.\nPgMultisearch.configure do |defaults, index|\n  plugin(:document)\n  plugin(:suggestions)\n  plugin(:age, column: 'provenance')\n\n  defaults.against            = index.projections(:tsearch, :date, :dmetaphone, :trigram)\n  defaults.ignoring           = :accents\n  defaults.prepared_statement = true\n  defaults.strategies do |strategies|\n    strategies.age do |age|\n      age.only = index.projections(:date)\n    end\n\n    strategies.dmetaphone do |dmetaphone|\n      dmetaphone.any_word         = false\n      dmetaphone.dictionary       = 'simple'\n      dmetaphone.negation         = true\n      dmetaphone.normalization    = 32\n      dmetaphone.only             = index.projections(:dmetaphone)\n      dmetaphone.prefix           = true\n      dmetaphone.tsquery_function = :to_tsquery\n      dmetaphone.tsrank_function  = :ts_rank\n      dmetaphone.tsvector_column  = index.projections(:dmetaphone)\n      dmetaphone.weights          = index.weights[0]\n    end\n\n    strategies.trigram do |trigram|\n      trigram.word_similarity = false\n    end\n\n    strategies.tsearch do |tsearch|\n      tsearch.any_word         = false\n      tsearch.dictionary       = 'english'\n      tsearch.negation         = true\n      tsearch.normalization    = 32\n      tsearch.only             = index.projections(:tsearch)\n      tsearch.prefix           = true\n      tsearch.tsquery_function = :to_tsquery\n      tsearch.tsrank_function  = :ts_rank\n      tsearch.tsvector_column  = index.projections(:tsearch)\n    end\n  end\nend\n\n# Configure `PgMultisearch::Index` scopes\nSearch.configure do |config, index| # rubocop:disable BlockLength\n  # The default scope\n  config.search do |scope|\n    scope.filter_by do |filter|\n      filter.primary   = index.strategy(:tsearch)\n      filter.secondary = index.strategy(:dmetaphone) # Sound alike\n      filter.tertiary  = index.strategy(:trigram)    # Fuzzy\n    end\n\n    scope.rank_by do |rank|\n      # Apply\n      rank.calculation = lambda { |primary, secondary, tertiary, ast|\n        ast.group(primary + ast.group(secondary * 0.2)) / 2\n      }\n\n      # Calculates the average of three scores\n      rank.primary   = index.strategy(:tsearch)\n      rank.secondary = index.strategy(:trigram)\n      rank.tertiary  = index.strategy(:dmetaphone)\n\n      # Refine the result set\n      rank.threshold = 0.3\n\n      # Apply rules per Indexable type\n      rank.polymorphic = {\n        # Ranks non qualified types by age (according to a date stored within the configured date column)\n        :default                  =\u003e index.strategy(:age),\n        # Calculates the average of two scores for records of type Organisation and Person\n        [%w(Organisation Person)] =\u003e index.strategies(\n          :tsearch, # primary\n          :trigram  # secondary\n        )\n      }\n    end\n\n    scope.strategies do |strategies|\n      strategies.age do |age|\n\n      end\n\n      strategies.tsearch do |tsearch|\n        tsearch.highlight do |highlight|\n          # Build the highlightable document from the denormalized data\n          highlight.document do |strategy, ast, table|\n            ast.fn.jsonb_fields_to_text(table[index.projection(:data)], ['field1', 'field2'])\n          end\n          # Or specify the fields to use\n          highlight.fields         = %w(title overview)\n          highlight.min_words      = 15\n          highlight.max_words      = 35\n          highlight.max_fragments  = 0\n          highlight.short_words    = 3\n          highlight.start_sel      = '\u003cb\u003e'\n          highlight.stop_sel       = '\u003c/b\u003e'\n        end\n      end\n    end\n  end\n\n  # Configure suggestions\n  config.suggestions do |scope|\n    scope.filter_by do |filter|\n      filter.primary = index.strategy(:dmetaphone) # index.strategy(:trigram)\n    end\n\n    scope.rank_by do |rank|\n      rank.primary = index.strategy(:dmetaphone) # index.strategy(:trigram)\n    end\n\n    scope.strategies do |strategies|\n      strategies.dmetaphone do |dmetaphone|\n        dmetaphone.any_word = true\n        dmetaphone.prefix   = true\n      end\n\n      strategies.trigram do |trigram|\n        trigram.word_similarity = true\n      end\n    end\n  end\nend\n```\n\n## Example\n\n```ruby\n  class Search\n    include ::PgMultisearch::Search\n  end\n\n  params  = {\n    'search' =\u003e 'query',\n    'type' =\u003e 'Organisation'\n  }\n  options = {\n    scope_name: :search,\n    preload:    true,\n    threshold:  0.6,\n    weights:    %w(A B)\n  }\n\n  # Initialize the Search delegator with request paramters and options\n  search = Search.call(params, options) # =\u003e #\u003cSearch\u003e\n\n  Search.call(params, scope_name: :suggestions, limit: 10).to_a\n\n  # Apply further refinements to the scope\n  search = Search.call(params, options) do |current_scope, builder|\n    current_scope\n      .where(%{ data -\u003e\u003e 'country' IN ('Saturn') })\n      .where(%{ data @\u003e '{\"name\":\"von\"}'::jsonb })\n      .where(type: %w(Oblong))\n      .page(page)\n  end\n\n  # Materialize the relation\n  search.to_a\n\n  # or Handle loading yourself\n  search.load do |relation|\n    relation.connection.select_values(relation.arel.to_sql, relation.klass, bind_params)\n\n    # or\n\n    res = relation.connection.execute(relation.arel.to_sql)\n    tuples = res.values\n    res.clear\n    tuples\n  end\n```\n\n## Index\n\nRebuild `bin/rake pg_multisearch:rebuild[model,schema]`\n\n## [TODO](TODO.md)\n\n## Development\n\nSpecs are defined within [`/spec`](/spec). Please submit relevant specs with your Pull Request.\n\nTo run tests:\n\n- Install [`Ruby \u003e= 2.2.2`](https://www.ruby-lang.org/en/documentation/installation/)\n- Create a local test database `pg_multisearch_test` PostgreSQL\n- Copy `spec/support/database.example.yml` to `spec/support/database.yml` and enter local credentials for the test database(s)\n- Install development dependencies using `bundle`\n- Run tests `bundle exec rspec`\n\nWe recommend to test large changes against multiple versions of Ruby and multiple dependency sets.\nSupported combinations are configured in `.travis.yml`. We provide some Rake tasks to help with this:\n\n- Install development dependencies using `bundle exec rake matrix:install`\n- Run tests `bundle exec rake matrix:spec`\n\nNote that we have configured `Travis CI` to automatically run tests in all supported Ruby versions and dependency sets after each push. We will only merge pull requests after a green Travis build.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiktur%2Fpg_multisearch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiktur%2Fpg_multisearch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiktur%2Fpg_multisearch/lists"}