Commit 54c48b92f0ef2d197369c03b6096bb3e19d6713e

Authored by Andrew Kane
1 parent f915ef75

Added generate mappings method

Showing 1 changed file with 135 additions and 130 deletions   Show diff stats
lib/searchkick/index_options.rb
@@ -23,138 +23,10 @@ module Searchkick @@ -23,138 +23,10 @@ module Searchkick
23 mappings = custom_mapping 23 mappings = custom_mapping
24 else 24 else
25 settings = generate_settings 25 settings = generate_settings
26 -  
27 - mapping = {}  
28 -  
29 - keyword_mapping = {type: "keyword"}  
30 - keyword_mapping[:ignore_above] = options[:ignore_above] || 30000  
31 -  
32 - # conversions  
33 - Array(options[:conversions]).each do |conversions_field|  
34 - mapping[conversions_field] = {  
35 - type: "nested",  
36 - properties: {  
37 - query: {type: default_type, analyzer: "searchkick_keyword"},  
38 - count: {type: "integer"}  
39 - }  
40 - }  
41 - end  
42 -  
43 - mapping_options = Hash[  
44 - [:suggest, :word, :text_start, :text_middle, :text_end, :word_start, :word_middle, :word_end, :highlight, :searchable, :filterable]  
45 - .map { |type| [type, (options[type] || []).map(&:to_s)] }  
46 - ]  
47 -  
48 - word = options[:word] != false && (!options[:match] || options[:match] == :word)  
49 -  
50 - mapping_options[:searchable].delete("_all")  
51 -  
52 - analyzed_field_options = {type: default_type, index: true, analyzer: default_analyzer}  
53 -  
54 - mapping_options.values.flatten.uniq.each do |field|  
55 - fields = {}  
56 -  
57 - if options.key?(:filterable) && !mapping_options[:filterable].include?(field)  
58 - fields[field] = {type: default_type, index: false}  
59 - else  
60 - fields[field] = keyword_mapping  
61 - end  
62 -  
63 - if !options[:searchable] || mapping_options[:searchable].include?(field)  
64 - if word  
65 - fields[:analyzed] = analyzed_field_options  
66 -  
67 - if mapping_options[:highlight].include?(field)  
68 - fields[:analyzed][:term_vector] = "with_positions_offsets"  
69 - end  
70 - end  
71 -  
72 - mapping_options.except(:highlight, :searchable, :filterable, :word).each do |type, f|  
73 - if options[:match] == type || f.include?(field)  
74 - fields[type] = {type: default_type, index: true, analyzer: "searchkick_#{type}_index"}  
75 - end  
76 - end  
77 - end  
78 -  
79 - mapping[field] = fields[field].merge(fields: fields.except(field))  
80 - end  
81 -  
82 - (options[:locations] || []).map(&:to_s).each do |field|  
83 - mapping[field] = {  
84 - type: "geo_point"  
85 - }  
86 - end  
87 -  
88 - options[:geo_shape] = options[:geo_shape].product([{}]).to_h if options[:geo_shape].is_a?(Array)  
89 - (options[:geo_shape] || {}).each do |field, shape_options|  
90 - mapping[field] = shape_options.merge(type: "geo_shape")  
91 - end  
92 -  
93 - if options[:inheritance]  
94 - mapping[:type] = keyword_mapping  
95 - end  
96 -  
97 - routing = {}  
98 - if options[:routing]  
99 - routing = {required: true}  
100 - unless options[:routing] == true  
101 - routing[:path] = options[:routing].to_s  
102 - end  
103 - end  
104 -  
105 - dynamic_fields = {  
106 - # analyzed field must be the default field for include_in_all  
107 - # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/  
108 - # however, we can include the not_analyzed field in _all  
109 - # and the _all index analyzer will take care of it  
110 - "{name}" => keyword_mapping  
111 - }  
112 -  
113 - if options.key?(:filterable)  
114 - dynamic_fields["{name}"] = {type: default_type, index: false}  
115 - end  
116 -  
117 - unless options[:searchable]  
118 - if options[:match] && options[:match] != :word  
119 - dynamic_fields[options[:match]] = {type: default_type, index: true, analyzer: "searchkick_#{options[:match]}_index"}  
120 - end  
121 -  
122 - if word  
123 - dynamic_fields[:analyzed] = analyzed_field_options  
124 - end  
125 - end  
126 -  
127 - # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/  
128 - multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))  
129 -  
130 - mappings = {  
131 - properties: mapping,  
132 - _routing: routing,  
133 - # https://gist.github.com/kimchy/2898285  
134 - dynamic_templates: [  
135 - {  
136 - string_template: {  
137 - match: "*",  
138 - match_mapping_type: "string",  
139 - mapping: multi_field  
140 - }  
141 - }  
142 - ]  
143 - }  
144 -  
145 - if below70  
146 - mappings = {index_type => mappings}  
147 - end  
148 -  
149 - mappings = mappings.symbolize_keys.deep_merge(custom_mapping.symbolize_keys) 26 + mappings = generate_mappings.symbolize_keys.deep_merge(custom_mapping.symbolize_keys)
150 end 27 end
151 28
152 - if options[:deep_paging]  
153 - if !settings.dig(:index, :max_result_window) && !settings[:"index.max_result_window"]  
154 - settings[:index] ||= {}  
155 - settings[:index][:max_result_window] = 1_000_000_000  
156 - end  
157 - end 29 + set_deep_paging(settings) if options[:deep_paging]
158 30
159 { 31 {
160 settings: settings, 32 settings: settings,
@@ -433,6 +305,132 @@ module Searchkick @@ -433,6 +305,132 @@ module Searchkick
433 settings 305 settings
434 end 306 end
435 307
  308 + def generate_mappings
  309 + mapping = {}
  310 +
  311 + keyword_mapping = {type: "keyword"}
  312 + keyword_mapping[:ignore_above] = options[:ignore_above] || 30000
  313 +
  314 + # conversions
  315 + Array(options[:conversions]).each do |conversions_field|
  316 + mapping[conversions_field] = {
  317 + type: "nested",
  318 + properties: {
  319 + query: {type: default_type, analyzer: "searchkick_keyword"},
  320 + count: {type: "integer"}
  321 + }
  322 + }
  323 + end
  324 +
  325 + mapping_options = Hash[
  326 + [:suggest, :word, :text_start, :text_middle, :text_end, :word_start, :word_middle, :word_end, :highlight, :searchable, :filterable]
  327 + .map { |type| [type, (options[type] || []).map(&:to_s)] }
  328 + ]
  329 +
  330 + word = options[:word] != false && (!options[:match] || options[:match] == :word)
  331 +
  332 + mapping_options[:searchable].delete("_all")
  333 +
  334 + analyzed_field_options = {type: default_type, index: true, analyzer: default_analyzer}
  335 +
  336 + mapping_options.values.flatten.uniq.each do |field|
  337 + fields = {}
  338 +
  339 + if options.key?(:filterable) && !mapping_options[:filterable].include?(field)
  340 + fields[field] = {type: default_type, index: false}
  341 + else
  342 + fields[field] = keyword_mapping
  343 + end
  344 +
  345 + if !options[:searchable] || mapping_options[:searchable].include?(field)
  346 + if word
  347 + fields[:analyzed] = analyzed_field_options
  348 +
  349 + if mapping_options[:highlight].include?(field)
  350 + fields[:analyzed][:term_vector] = "with_positions_offsets"
  351 + end
  352 + end
  353 +
  354 + mapping_options.except(:highlight, :searchable, :filterable, :word).each do |type, f|
  355 + if options[:match] == type || f.include?(field)
  356 + fields[type] = {type: default_type, index: true, analyzer: "searchkick_#{type}_index"}
  357 + end
  358 + end
  359 + end
  360 +
  361 + mapping[field] = fields[field].merge(fields: fields.except(field))
  362 + end
  363 +
  364 + (options[:locations] || []).map(&:to_s).each do |field|
  365 + mapping[field] = {
  366 + type: "geo_point"
  367 + }
  368 + end
  369 +
  370 + options[:geo_shape] = options[:geo_shape].product([{}]).to_h if options[:geo_shape].is_a?(Array)
  371 + (options[:geo_shape] || {}).each do |field, shape_options|
  372 + mapping[field] = shape_options.merge(type: "geo_shape")
  373 + end
  374 +
  375 + if options[:inheritance]
  376 + mapping[:type] = keyword_mapping
  377 + end
  378 +
  379 + routing = {}
  380 + if options[:routing]
  381 + routing = {required: true}
  382 + unless options[:routing] == true
  383 + routing[:path] = options[:routing].to_s
  384 + end
  385 + end
  386 +
  387 + dynamic_fields = {
  388 + # analyzed field must be the default field for include_in_all
  389 + # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
  390 + # however, we can include the not_analyzed field in _all
  391 + # and the _all index analyzer will take care of it
  392 + "{name}" => keyword_mapping
  393 + }
  394 +
  395 + if options.key?(:filterable)
  396 + dynamic_fields["{name}"] = {type: default_type, index: false}
  397 + end
  398 +
  399 + unless options[:searchable]
  400 + if options[:match] && options[:match] != :word
  401 + dynamic_fields[options[:match]] = {type: default_type, index: true, analyzer: "searchkick_#{options[:match]}_index"}
  402 + end
  403 +
  404 + if word
  405 + dynamic_fields[:analyzed] = analyzed_field_options
  406 + end
  407 + end
  408 +
  409 + # http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
  410 + multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
  411 +
  412 + mappings = {
  413 + properties: mapping,
  414 + _routing: routing,
  415 + # https://gist.github.com/kimchy/2898285
  416 + dynamic_templates: [
  417 + {
  418 + string_template: {
  419 + match: "*",
  420 + match_mapping_type: "string",
  421 + mapping: multi_field
  422 + }
  423 + }
  424 + ]
  425 + }
  426 +
  427 + if below70
  428 + mappings = {index_type => mappings}
  429 + end
  430 +
  431 + mappings
  432 + end
  433 +
436 def add_synonyms(settings) 434 def add_synonyms(settings)
437 synonyms = options[:synonyms] || [] 435 synonyms = options[:synonyms] || []
438 synonyms = synonyms.call if synonyms.respond_to?(:call) 436 synonyms = synonyms.call if synonyms.respond_to?(:call)
@@ -499,6 +497,13 @@ module Searchkick @@ -499,6 +497,13 @@ module Searchkick
499 end 497 end
500 end 498 end
501 499
  500 + def set_deep_paging(settings)
  501 + if !settings.dig(:index, :max_result_window) && !settings[:"index.max_result_window"]
  502 + settings[:index] ||= {}
  503 + settings[:index][:max_result_window] = 1_000_000_000
  504 + end
  505 + end
  506 +
502 def default_type 507 def default_type
503 "text" 508 "text"
504 end 509 end