pg_search 2.3.6 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +47 -35
- data/.github/workflows/codeql.yml +87 -0
- data/.standard.yml +6 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +21 -6
- data/LICENSE +1 -1
- data/README.md +133 -114
- data/Rakefile +4 -13
- data/lib/pg_search/configuration/column.rb +6 -4
- data/lib/pg_search/configuration/foreign_column.rb +1 -1
- data/lib/pg_search/configuration.rb +11 -27
- data/lib/pg_search/document.rb +8 -8
- data/lib/pg_search/features/dmetaphone.rb +1 -1
- data/lib/pg_search/features/trigram.rb +4 -4
- data/lib/pg_search/features/tsearch.rb +23 -30
- data/lib/pg_search/migration/dmetaphone_generator.rb +2 -2
- data/lib/pg_search/migration/generator.rb +5 -5
- data/lib/pg_search/migration/multisearch_generator.rb +2 -2
- data/lib/pg_search/model.rb +12 -14
- data/lib/pg_search/multisearch/rebuilder.rb +4 -3
- data/lib/pg_search/multisearch.rb +4 -2
- data/lib/pg_search/multisearchable.rb +7 -7
- data/lib/pg_search/normalizer.rb +17 -7
- data/lib/pg_search/scope_options.rb +36 -8
- data/lib/pg_search/tasks.rb +2 -2
- data/lib/pg_search/version.rb +1 -1
- data/lib/pg_search.rb +3 -3
- data/pg_search.gemspec +16 -31
- data/spec/integration/associations_spec.rb +118 -106
- data/spec/integration/deprecation_spec.rb +12 -9
- data/spec/integration/pagination_spec.rb +1 -0
- data/spec/integration/pg_search_spec.rb +343 -298
- data/spec/integration/single_table_inheritance_spec.rb +7 -5
- data/spec/lib/pg_search/configuration/association_spec.rb +17 -15
- data/spec/lib/pg_search/configuration/column_spec.rb +13 -1
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +5 -4
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +4 -4
- data/spec/lib/pg_search/features/trigram_spec.rb +32 -33
- data/spec/lib/pg_search/features/tsearch_spec.rb +57 -39
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +70 -20
- data/spec/lib/pg_search/multisearch_spec.rb +8 -8
- data/spec/lib/pg_search/multisearchable_spec.rb +34 -26
- data/spec/lib/pg_search/normalizer_spec.rb +11 -11
- data/spec/lib/pg_search_spec.rb +22 -18
- data/spec/spec_helper.rb +3 -18
- data/spec/support/database.rb +6 -6
- metadata +11 -219
- data/.codeclimate.yml +0 -17
- data/.rubocop.yml +0 -137
- data/.travis.yml +0 -37
- data/spec/.rubocop.yml +0 -14
- data/spec/integration/.rubocop.yml +0 -11
data/README.md
CHANGED
|
@@ -13,10 +13,10 @@ Read the blog post introducing PgSearch at https://tanzu.vmware.com/content/blog
|
|
|
13
13
|
|
|
14
14
|
## REQUIREMENTS
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
- Ruby 3.3+
|
|
17
|
+
- Active Record 7.2+
|
|
18
|
+
- PostgreSQL 9.2+
|
|
19
|
+
- [PostgreSQL extensions](https://github.com/Casecommons/pg_search/wiki/Installing-PostgreSQL-Extensions) for certain features
|
|
20
20
|
|
|
21
21
|
## INSTALL
|
|
22
22
|
|
|
@@ -48,48 +48,49 @@ To add PgSearch to an Active Record model, simply include the PgSearch module.
|
|
|
48
48
|
class Shape < ActiveRecord::Base
|
|
49
49
|
include PgSearch::Model
|
|
50
50
|
end
|
|
51
|
-
```
|
|
51
|
+
```
|
|
52
52
|
|
|
53
53
|
### Contents
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
54
|
+
|
|
55
|
+
- [Multi-search vs. search scopes](#multi-search-vs-search-scopes)
|
|
56
|
+
- [Multi-search](#multi-search)
|
|
57
|
+
- [Setup](#setup)
|
|
58
|
+
- [`multisearchable`](#multisearchable)
|
|
59
|
+
- [More Options ](#more-options)
|
|
60
|
+
- [Multi-search associations](#multi-search-associations)
|
|
61
|
+
- [Searching in the global search index](#searching-in-the-global-search-index)
|
|
62
|
+
- [Chaining method calls onto the results](#chaining-method-calls-onto-the-results)
|
|
63
|
+
- [Configuring multi-search](#configuring-multi-search)
|
|
64
|
+
- [Rebuilding search documents for a given class](#rebuilding-search-documents-for-a-given-class)
|
|
65
|
+
- [Disabling multi-search indexing temporarily](#disabling-multi-search-indexing-temporarily)
|
|
66
|
+
- [`pg_search_scope`](#pg_search_scope)
|
|
67
|
+
- [Searching against one column](#searching-against-one-column)
|
|
68
|
+
- [Searching against multiple columns](#searching-against-multiple-columns)
|
|
69
|
+
- [Dynamic search scopes](#dynamic-search-scopes)
|
|
70
|
+
- [Searching through associations](#searching-through-associations)
|
|
71
|
+
- [Searching using different search features](#searching-using-different-search-features)
|
|
72
|
+
- [`:tsearch` (Full Text Search)](#tsearch-full-text-search)
|
|
73
|
+
- [Weighting](#weighting)
|
|
74
|
+
- [`:prefix` (PostgreSQL 8.4 and newer only)](#prefix-postgresql-84-and-newer-only)
|
|
75
|
+
- [`:negation`](#negation)
|
|
76
|
+
- [`:dictionary`](#dictionary)
|
|
77
|
+
- [`:normalization`](#normalization)
|
|
78
|
+
- [`:any_word`](#any_word)
|
|
79
|
+
- [`:sort_only`](#sort_only)
|
|
80
|
+
- [`:highlight`](#highlight)
|
|
81
|
+
- [`:dmetaphone` (Double Metaphone soundalike search)](#dmetaphone-double-metaphone-soundalike-search)
|
|
82
|
+
- [`:trigram` (Trigram search)](#trigram-trigram-search)
|
|
83
|
+
- [`:threshold`](#threshold)
|
|
84
|
+
- [`:word_similarity`](#word_similarity)
|
|
85
|
+
- [Limiting Fields When Combining Features](#limiting-fields-when-combining-features)
|
|
86
|
+
- [Ignoring accent marks](#ignoring-accent-marks)
|
|
87
|
+
- [Using tsvector columns](#using-tsvector-columns)
|
|
88
|
+
- [Combining multiple tsvectors](#combining-multiple-tsvectors)
|
|
89
|
+
- [Configuring ranking and ordering](#configuring-ranking-and-ordering)
|
|
90
|
+
- [`:ranked_by` (Choosing a ranking algorithm)](#ranked_by-choosing-a-ranking-algorithm)
|
|
91
|
+
- [`:order_within_rank` (Breaking ties)](#order_within_rank-breaking-ties)
|
|
92
|
+
- [`PgSearch#pg_search_rank` (Reading a record's rank as a Float)](#pgsearchpg_search_rank-reading-a-records-rank-as-a-float)
|
|
93
|
+
- [Search rank and chained scopes](#search-rank-and-chained-scopes)
|
|
93
94
|
|
|
94
95
|
### Multi-search vs. search scopes
|
|
95
96
|
|
|
@@ -198,17 +199,22 @@ problematic_record.published? # => true
|
|
|
198
199
|
PgSearch.multisearch("timestamp") # => Includes problematic_record
|
|
199
200
|
```
|
|
200
201
|
|
|
201
|
-
#### More Options
|
|
202
|
+
#### More Options
|
|
202
203
|
|
|
203
204
|
**Conditionally update pg_search_documents**
|
|
204
205
|
|
|
205
|
-
You can
|
|
206
|
+
You can also use the `:update_if` option to pass a Proc or method name to call
|
|
207
|
+
to determine whether or not a particular record should be updated.
|
|
208
|
+
|
|
209
|
+
Note that the Proc or method name is called in an `after_save` hook, so if you
|
|
210
|
+
are relying on ActiveRecord dirty flags use `*_previously_changed?`.
|
|
206
211
|
|
|
207
212
|
```ruby
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
class Message < ActiveRecord::Base
|
|
214
|
+
include PgSearch::Model
|
|
215
|
+
multisearchable against: [:body],
|
|
216
|
+
update_if: :body_previously_changed?
|
|
217
|
+
end
|
|
212
218
|
```
|
|
213
219
|
|
|
214
220
|
**Specify additional attributes to be saved on the pg_search_documents table**
|
|
@@ -241,7 +247,8 @@ This allows much faster searches without joins later on by doing something like:
|
|
|
241
247
|
PgSearch.multisearch(params['search']).where(author_id: 2)
|
|
242
248
|
```
|
|
243
249
|
|
|
244
|
-
|
|
250
|
+
_NOTE: You must currently manually call `record.update_pg_search_document` for
|
|
251
|
+
the additional attribute to be included in the pg_search_documents table_
|
|
245
252
|
|
|
246
253
|
#### Multi-search associations
|
|
247
254
|
|
|
@@ -325,18 +332,18 @@ To regenerate the documents for a given class, run:
|
|
|
325
332
|
PgSearch::Multisearch.rebuild(Product)
|
|
326
333
|
```
|
|
327
334
|
|
|
328
|
-
The
|
|
335
|
+
The `rebuild` method will delete all the documents for the given class
|
|
329
336
|
before regenerating them. In some situations this may not be desirable,
|
|
330
|
-
such as when you're using single-table inheritance and
|
|
331
|
-
is your base class. You can prevent
|
|
337
|
+
such as when you're using single-table inheritance and `searchable_type`
|
|
338
|
+
is your base class. You can prevent `rebuild` from deleting your records
|
|
332
339
|
like so:
|
|
333
340
|
|
|
334
341
|
```ruby
|
|
335
342
|
PgSearch::Multisearch.rebuild(Product, clean_up: false)
|
|
336
343
|
```
|
|
337
344
|
|
|
338
|
-
|
|
339
|
-
you can pass
|
|
345
|
+
`rebuild` runs inside a single transaction. To run outside of a transaction,
|
|
346
|
+
you can pass `transactional: false` like so:
|
|
340
347
|
|
|
341
348
|
```ruby
|
|
342
349
|
PgSearch::Multisearch.rebuild(Product, transactional: false)
|
|
@@ -353,15 +360,11 @@ pg_search_documents tables. The following will set the schema search path to
|
|
|
353
360
|
|
|
354
361
|
$ rake pg_search:multisearch:rebuild[BlogPost,my_schema]
|
|
355
362
|
|
|
356
|
-
For models that are multisearchable
|
|
363
|
+
For models that are multisearchable `:against` methods that directly map to
|
|
357
364
|
Active Record attributes, an efficient single SQL statement is run to update
|
|
358
|
-
the pg_search_documents table all at once. However, if you call any dynamic
|
|
359
|
-
methods in
|
|
360
|
-
|
|
361
|
-
```ruby
|
|
362
|
-
PgSearch::Document.delete_all(searchable_type: "Ingredient")
|
|
363
|
-
Ingredient.find_each { |record| record.update_pg_search_document }
|
|
364
|
-
```
|
|
365
|
+
the `pg_search_documents` table all at once. However, if you call any dynamic
|
|
366
|
+
methods in `:against` then `update_pg_search_document` will be called on the
|
|
367
|
+
individual records being indexed in batches.
|
|
365
368
|
|
|
366
369
|
You can also provide a custom implementation for rebuilding the documents by
|
|
367
370
|
adding a class method called `rebuild_pg_search_documents` to your model.
|
|
@@ -397,7 +400,8 @@ class Movie < ActiveRecord::Base
|
|
|
397
400
|
end
|
|
398
401
|
end
|
|
399
402
|
```
|
|
400
|
-
|
|
403
|
+
|
|
404
|
+
**Note:** If using PostgreSQL before 9.1, replace the `CONCAT_WS()` function call with double-pipe concatenation, eg. `(movies.name || ' ' || directors.name)`. However, now be aware that if _any_ of the joined values is NULL then the final `content` value will also be NULL, whereas `CONCAT_WS()` will selectively ignore NULL values.
|
|
401
405
|
|
|
402
406
|
#### Disabling multi-search indexing temporarily
|
|
403
407
|
|
|
@@ -550,13 +554,27 @@ class Beer < ActiveRecord::Base
|
|
|
550
554
|
end
|
|
551
555
|
```
|
|
552
556
|
|
|
553
|
-
|
|
557
|
+
Here's an example if you pass multiple :using options with additional configurations.
|
|
558
|
+
|
|
559
|
+
```ruby
|
|
560
|
+
class Beer < ActiveRecord::Base
|
|
561
|
+
include PgSearch::Model
|
|
562
|
+
pg_search_scope :search_name,
|
|
563
|
+
against: :name,
|
|
564
|
+
using: {
|
|
565
|
+
:trigram => {},
|
|
566
|
+
:dmetaphone => {},
|
|
567
|
+
:tsearch => { :prefix => true }
|
|
568
|
+
}
|
|
569
|
+
end
|
|
570
|
+
```
|
|
554
571
|
|
|
555
|
-
|
|
556
|
-
* :trigram - [Trigram search](http://www.postgresql.org/docs/current/static/pgtrgm.html), which
|
|
557
|
-
requires the trigram extension
|
|
558
|
-
* :dmetaphone - [Double Metaphone search](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html#AEN177521), which requires the fuzzystrmatch extension
|
|
572
|
+
The currently implemented features are
|
|
559
573
|
|
|
574
|
+
- :tsearch - [Full text search](http://www.postgresql.org/docs/current/static/textsearch-intro.html), which is built-in to PostgreSQL
|
|
575
|
+
- :trigram - [Trigram search](http://www.postgresql.org/docs/current/static/pgtrgm.html), which
|
|
576
|
+
requires the trigram extension
|
|
577
|
+
- :dmetaphone - [Double Metaphone search](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html#AEN177521), which requires the fuzzystrmatch extension
|
|
560
578
|
|
|
561
579
|
#### :tsearch (Full Text Search)
|
|
562
580
|
|
|
@@ -564,6 +582,7 @@ PostgreSQL's built-in full text search supports weighting, prefix searches,
|
|
|
564
582
|
and stemming in multiple languages.
|
|
565
583
|
|
|
566
584
|
##### Weighting
|
|
585
|
+
|
|
567
586
|
Each searchable column can be given a weight of "A", "B", "C", or "D". Columns
|
|
568
587
|
with earlier letters are weighted higher than those with later letters. So, in
|
|
569
588
|
the following example, the title is the most important, followed by the
|
|
@@ -627,6 +646,7 @@ robin = Superhero.create name: 'Robin'
|
|
|
627
646
|
|
|
628
647
|
Superhero.whose_name_starts_with("Bat") # => [batman, batgirl]
|
|
629
648
|
```
|
|
649
|
+
|
|
630
650
|
##### :negation
|
|
631
651
|
|
|
632
652
|
PostgreSQL's full text search matches all search terms by default. If you want
|
|
@@ -662,7 +682,7 @@ Animal.with_name_matching("fish !red !blue") # => [one_fish, two_fish]
|
|
|
662
682
|
|
|
663
683
|
PostgreSQL full text search also support multiple dictionaries for stemming.
|
|
664
684
|
You can learn more about how dictionaries work by reading the [PostgreSQL
|
|
665
|
-
documention](http://www.postgresql.org/docs/current/static/textsearch-dictionaries.html).
|
|
685
|
+
documention](http://www.postgresql.org/docs/current/static/textsearch-dictionaries.html).
|
|
666
686
|
If you use one of the language dictionaries, such as "english",
|
|
667
687
|
then variants of words (e.g. "jumping" and "jumped") will match each other. If
|
|
668
688
|
you don't want stemming, you should pick the "simple" dictionary which does
|
|
@@ -684,12 +704,12 @@ class BoringTweet < ActiveRecord::Base
|
|
|
684
704
|
}
|
|
685
705
|
end
|
|
686
706
|
|
|
687
|
-
|
|
707
|
+
sleep = BoringTweet.create! text: "I snoozed my alarm for fourteen hours today. I bet I can beat that tomorrow! #sleep"
|
|
688
708
|
sleeping = BoringTweet.create! text: "You know what I like? Sleeping. That's what. #enjoyment"
|
|
689
|
-
|
|
709
|
+
sleeps = BoringTweet.create! text: "In the jungle, the mighty jungle, the lion sleeps #tonight"
|
|
690
710
|
|
|
691
|
-
BoringTweet.kinda_matching("sleeping") # => [
|
|
692
|
-
BoringTweet.literally_matching("
|
|
711
|
+
BoringTweet.kinda_matching("sleeping") # => [sleep, sleeping, sleeps]
|
|
712
|
+
BoringTweet.literally_matching("sleeps") # => [sleeps]
|
|
693
713
|
```
|
|
694
714
|
|
|
695
715
|
##### :normalization
|
|
@@ -787,7 +807,6 @@ Person.search('ash hines') # => [exact, one_exact_one_close, one_exact]
|
|
|
787
807
|
Adding .with_pg_search_highlight after the pg_search_scope you can access to
|
|
788
808
|
`pg_highlight` attribute for each object.
|
|
789
809
|
|
|
790
|
-
|
|
791
810
|
```ruby
|
|
792
811
|
class Person < ActiveRecord::Base
|
|
793
812
|
include PgSearch::Model
|
|
@@ -798,8 +817,8 @@ class Person < ActiveRecord::Base
|
|
|
798
817
|
highlight: {
|
|
799
818
|
StartSel: '<b>',
|
|
800
819
|
StopSel: '</b>',
|
|
801
|
-
|
|
802
|
-
|
|
820
|
+
MinWords: 123,
|
|
821
|
+
MaxWords: 456,
|
|
803
822
|
ShortWord: 4,
|
|
804
823
|
HighlightAll: true,
|
|
805
824
|
MaxFragments: 3,
|
|
@@ -834,7 +853,7 @@ used for searching.
|
|
|
834
853
|
Double Metaphone support is currently available as part of the [fuzzystrmatch
|
|
835
854
|
extension](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html)
|
|
836
855
|
that must be installed before this feature can be used. In addition to the
|
|
837
|
-
extension, you must install a utility function into your database. To generate
|
|
856
|
+
extension, you must install a utility function into your database. To generate
|
|
838
857
|
and run a migration for this, run:
|
|
839
858
|
|
|
840
859
|
$ rails g pg_search:migration:dmetaphone
|
|
@@ -869,7 +888,7 @@ Trigram search works by counting how many three-letter substrings (or
|
|
|
869
888
|
Trigram search has some ability to work even with typos and misspellings in
|
|
870
889
|
the query or text.
|
|
871
890
|
|
|
872
|
-
Trigram support is currently available as part of the
|
|
891
|
+
Trigram support is currently available as part of the
|
|
873
892
|
[pg_trgm extension](http://www.postgresql.org/docs/current/static/pgtrgm.html) that must be installed before this
|
|
874
893
|
feature can be used.
|
|
875
894
|
|
|
@@ -933,7 +952,7 @@ Vegetable.strictly_spelled_like("collyflower") # => []
|
|
|
933
952
|
Allows you to match words in longer strings.
|
|
934
953
|
By default, trigram searches use `%` or `similarity()` as a similarity value.
|
|
935
954
|
Set `word_similarity` to `true` to opt for `<%` and `word_similarity` instead.
|
|
936
|
-
This causes the trigram search to use the similarity of the query term
|
|
955
|
+
This causes the trigram search to use the similarity of the query term
|
|
937
956
|
and the word with greatest similarity.
|
|
938
957
|
|
|
939
958
|
```ruby
|
|
@@ -959,12 +978,12 @@ Sentence.similarity_like("word") # => []
|
|
|
959
978
|
Sentence.word_similarity_like("word") # => [sentence]
|
|
960
979
|
```
|
|
961
980
|
|
|
962
|
-
### Limiting Fields When Combining Features
|
|
981
|
+
### Limiting Fields When Combining Features
|
|
963
982
|
|
|
964
|
-
Sometimes when doing queries combining different features you
|
|
965
|
-
might want to
|
|
983
|
+
Sometimes when doing queries combining different features you
|
|
984
|
+
might want to search against only some of the fields with certain features.
|
|
966
985
|
For example perhaps you want to only do a trigram search against the shorter fields
|
|
967
|
-
so that you don't need to reduce the threshold excessively. You can specify
|
|
986
|
+
so that you don't need to reduce the threshold excessively. You can specify
|
|
968
987
|
which fields using the 'only' option:
|
|
969
988
|
|
|
970
989
|
```ruby
|
|
@@ -983,7 +1002,7 @@ class Image < ActiveRecord::Base
|
|
|
983
1002
|
end
|
|
984
1003
|
```
|
|
985
1004
|
|
|
986
|
-
Now you can succesfully retrieve an Image with a file_name: 'image_foo.jpg'
|
|
1005
|
+
Now you can succesfully retrieve an Image with a file_name: 'image_foo.jpg'
|
|
987
1006
|
and long_description: 'This description is so long that it would make a trigram search
|
|
988
1007
|
fail any reasonable threshold limit' with:
|
|
989
1008
|
|
|
@@ -1036,31 +1055,31 @@ as it offloads creation of the tsvector that the tsquery is evaluated against.
|
|
|
1036
1055
|
|
|
1037
1056
|
To use this functionality you'll need to do a few things:
|
|
1038
1057
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1058
|
+
- Create a column of type tsvector that you'd like to search against. If you
|
|
1059
|
+
want to search using multiple search methods, for example tsearch and
|
|
1060
|
+
dmetaphone, you'll need a column for each.
|
|
1061
|
+
- Create a trigger function that will update the column(s) using the
|
|
1062
|
+
expression appropriate for that type of search. See:
|
|
1063
|
+
[the PostgreSQL documentation for text search triggers](http://www.postgresql.org/docs/current/static/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS)
|
|
1064
|
+
- Should you have any pre-existing data in the table, update the
|
|
1065
|
+
newly-created tsvector columns with the expression that your trigger
|
|
1066
|
+
function uses.
|
|
1067
|
+
- Add the option to pg_search_scope, e.g:
|
|
1068
|
+
|
|
1069
|
+
```ruby
|
|
1070
|
+
pg_search_scope :fast_content_search,
|
|
1071
|
+
against: :content,
|
|
1072
|
+
using: {
|
|
1073
|
+
dmetaphone: {
|
|
1074
|
+
tsvector_column: 'tsvector_content_dmetaphone'
|
|
1075
|
+
},
|
|
1076
|
+
tsearch: {
|
|
1077
|
+
dictionary: 'english',
|
|
1078
|
+
tsvector_column: 'tsvector_content_tsearch'
|
|
1079
|
+
},
|
|
1080
|
+
trigram: {} # trigram does not use tsvectors
|
|
1081
|
+
}
|
|
1082
|
+
```
|
|
1064
1083
|
|
|
1065
1084
|
Please note that the :against column is only used when the tsvector_column is
|
|
1066
1085
|
not present for the search type.
|
|
@@ -1173,9 +1192,9 @@ shirt_brands[1].pg_search_rank #=> 0.0607927
|
|
|
1173
1192
|
|
|
1174
1193
|
#### Search rank and chained scopes
|
|
1175
1194
|
|
|
1176
|
-
Each PgSearch scope generates a named subquery for the search rank.
|
|
1195
|
+
Each PgSearch scope generates a named subquery for the search rank. If you
|
|
1177
1196
|
chain multiple scopes then PgSearch will generate a ranking query for each
|
|
1178
|
-
scope, so the ranking queries must have unique names.
|
|
1197
|
+
scope, so the ranking queries must have unique names. If you need to reference
|
|
1179
1198
|
the ranking query (e.g. in a GROUP BY clause) you can regenerate the subquery
|
|
1180
1199
|
name with the `PgScope::Configuration.alias` method by passing the name of the
|
|
1181
1200
|
queried table.
|
|
@@ -1201,5 +1220,5 @@ for discussing pg_search and other Casebook PBC open source projects.
|
|
|
1201
1220
|
|
|
1202
1221
|
## LICENSE
|
|
1203
1222
|
|
|
1204
|
-
Copyright © 2010–
|
|
1223
|
+
Copyright © 2010–2022 [Casebook PBC](http://www.casebook.net).
|
|
1205
1224
|
Licensed under the MIT license, see [LICENSE](/LICENSE) file.
|
data/Rakefile
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "bundler"
|
|
4
4
|
Bundler::GemHelper.install_tasks
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "rspec/core/rake_task"
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec)
|
|
8
8
|
|
|
9
|
-
require "
|
|
10
|
-
RuboCop::RakeTask.new do |t|
|
|
11
|
-
t.options = %w[--display-cop-names]
|
|
12
|
-
end
|
|
9
|
+
require "standard/rake"
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
task :undercover do
|
|
16
|
-
system("git fetch --unshallow") if ENV["CI"]
|
|
17
|
-
exit(1) unless system("bin/undercover --compare origin/master")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
task default: %w[spec rubocop undercover]
|
|
11
|
+
task default: %w[spec standard]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "digest"
|
|
4
4
|
|
|
5
5
|
module PgSearch
|
|
6
6
|
class Configuration
|
|
@@ -9,18 +9,20 @@ module PgSearch
|
|
|
9
9
|
|
|
10
10
|
def initialize(column_name, weight, model)
|
|
11
11
|
@name = column_name.to_s
|
|
12
|
-
@column_name = column_name
|
|
12
|
+
@column_name = column_name
|
|
13
13
|
@weight = weight
|
|
14
14
|
@model = model
|
|
15
15
|
@connection = model.connection
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def full_name
|
|
19
|
+
return @column_name if @column_name.is_a?(Arel::Nodes::SqlLiteral)
|
|
20
|
+
|
|
19
21
|
"#{table_name}.#{column_name}"
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def to_sql
|
|
23
|
-
"coalesce(#{expression}::text, '')"
|
|
25
|
+
"coalesce((#{expression})::text, '')"
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
private
|
|
@@ -30,7 +32,7 @@ module PgSearch
|
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def column_name
|
|
33
|
-
@connection.quote_column_name(@
|
|
35
|
+
@connection.quote_column_name(@name)
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
def expression
|
|
@@ -23,9 +23,7 @@ module PgSearch
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def columns
|
|
27
|
-
regular_columns + associated_columns
|
|
28
|
-
end
|
|
26
|
+
def columns = regular_columns + associated_columns
|
|
29
27
|
|
|
30
28
|
def regular_columns
|
|
31
29
|
return [] unless options[:against]
|
|
@@ -43,46 +41,31 @@ module PgSearch
|
|
|
43
41
|
end.flatten
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
def associated_columns
|
|
47
|
-
associations.map(&:columns).flatten
|
|
48
|
-
end
|
|
44
|
+
def associated_columns = associations.map(&:columns).flatten
|
|
49
45
|
|
|
50
|
-
def query
|
|
51
|
-
options[:query].to_s
|
|
52
|
-
end
|
|
46
|
+
def query = options[:query].to_s
|
|
53
47
|
|
|
54
|
-
def ignore
|
|
55
|
-
Array(options[:ignoring])
|
|
56
|
-
end
|
|
48
|
+
def ignore = Array(options[:ignoring])
|
|
57
49
|
|
|
58
|
-
def ranking_sql
|
|
59
|
-
options[:ranked_by]
|
|
60
|
-
end
|
|
50
|
+
def ranking_sql = options[:ranked_by]
|
|
61
51
|
|
|
62
|
-
def features
|
|
63
|
-
Array(options[:using])
|
|
64
|
-
end
|
|
52
|
+
def features = Array(options[:using])
|
|
65
53
|
|
|
66
54
|
def feature_options
|
|
67
|
-
@feature_options ||=
|
|
68
|
-
features.map do |feature_name, feature_options|
|
|
69
|
-
hash[feature_name] = feature_options
|
|
70
|
-
end
|
|
71
|
-
end
|
|
55
|
+
@feature_options ||= features.to_h { |name, opts| [name, opts] }
|
|
72
56
|
end
|
|
73
57
|
|
|
74
|
-
def order_within_rank
|
|
75
|
-
options[:order_within_rank]
|
|
76
|
-
end
|
|
58
|
+
def order_within_rank = options[:order_within_rank]
|
|
77
59
|
|
|
78
60
|
private
|
|
79
61
|
|
|
80
62
|
attr_reader :options
|
|
81
63
|
|
|
82
64
|
def default_options
|
|
83
|
-
{
|
|
65
|
+
{using: :tsearch}
|
|
84
66
|
end
|
|
85
67
|
|
|
68
|
+
# standard:disable Lint/UselessConstantScoping
|
|
86
69
|
VALID_KEYS = %w[
|
|
87
70
|
against ranked_by ignoring using query associated_against order_within_rank
|
|
88
71
|
].map(&:to_sym)
|
|
@@ -90,6 +73,7 @@ module PgSearch
|
|
|
90
73
|
VALID_VALUES = {
|
|
91
74
|
ignoring: [:accents]
|
|
92
75
|
}.freeze
|
|
76
|
+
# standard:enable Lint/UselessConstantScoping
|
|
93
77
|
|
|
94
78
|
def assert_valid_options(options)
|
|
95
79
|
unless options[:against] || options[:associated_against] || using_tsvector_column?(options[:using])
|
data/lib/pg_search/document.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "logger"
|
|
4
4
|
|
|
5
5
|
module PgSearch
|
|
6
|
-
class Document < ActiveRecord::Base
|
|
6
|
+
class Document < ActiveRecord::Base # standard:disable Rails/ApplicationRecord
|
|
7
7
|
include PgSearch::Model
|
|
8
8
|
|
|
9
|
-
self.table_name =
|
|
9
|
+
self.table_name = "pg_search_documents"
|
|
10
10
|
belongs_to :searchable, polymorphic: true
|
|
11
11
|
|
|
12
12
|
# The logger might not have loaded yet.
|
|
@@ -17,12 +17,12 @@ module PgSearch
|
|
|
17
17
|
|
|
18
18
|
pg_search_scope :search, lambda { |*args|
|
|
19
19
|
options = if PgSearch.multisearch_options.respond_to?(:call)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
PgSearch.multisearch_options.call(*args)
|
|
21
|
+
else
|
|
22
|
+
{query: args.first}.merge(PgSearch.multisearch_options)
|
|
23
|
+
end
|
|
24
24
|
|
|
25
|
-
{
|
|
25
|
+
{against: :content}.merge(options)
|
|
26
26
|
}
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -7,7 +7,7 @@ module PgSearch
|
|
|
7
7
|
class DMetaphone
|
|
8
8
|
def initialize(query, options, columns, model, normalizer)
|
|
9
9
|
dmetaphone_normalizer = Normalizer.new(normalizer)
|
|
10
|
-
options = (options || {}).merge(dictionary:
|
|
10
|
+
options = (options || {}).merge(dictionary: "simple")
|
|
11
11
|
@tsearch = TSearch.new(query, options, columns, model, dmetaphone_normalizer)
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -35,17 +35,17 @@ module PgSearch
|
|
|
35
35
|
|
|
36
36
|
def similarity_function
|
|
37
37
|
if word_similarity?
|
|
38
|
-
|
|
38
|
+
"word_similarity"
|
|
39
39
|
else
|
|
40
|
-
|
|
40
|
+
"similarity"
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def infix_operator
|
|
45
45
|
if word_similarity?
|
|
46
|
-
|
|
46
|
+
"<%"
|
|
47
47
|
else
|
|
48
|
-
|
|
48
|
+
"%"
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|