tire 0.1.16 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,29 +1,33 @@
1
1
  Tire
2
2
  =========
3
3
 
4
- _Tire_ is a Ruby client for the [ElasticSearch](http://www.elasticsearch.org/) search engine/database.
4
+ _Tire_ is a Ruby (1.8 or 1.9) client for the [ElasticSearch](http://www.elasticsearch.org/)
5
+ search engine/database.
5
6
 
6
7
  _ElasticSearch_ is a scalable, distributed, cloud-ready, highly-available,
7
- full-text search engine and database, communicating by JSON over RESTful HTTP,
8
- based on [Lucene](http://lucene.apache.org/), written in Java.
8
+ full-text search engine and database with
9
+ [powerfull aggregation features](http://www.elasticsearch.org/guide/reference/api/search/facets/),
10
+ communicating by JSON over RESTful HTTP, based on [Lucene](http://lucene.apache.org/), written in Java.
9
11
 
10
- This document provides just a brief overview of _Tire's_ features. Be sure to check out also
11
- the extensive documentation at <http://karmi.github.com/tire/> if you're interested.
12
+ This Readme provides a brief overview of _Tire's_ features. The more detailed documentation is at <http://karmi.github.com/tire/>.
13
+
14
+ Both of these documents contain a lot of information. Please set aside some time to read them thoroughly, before you blindly dive into „somehow making it work“. Just skimming through it **won't work** for you. For more information, please refer to the [integration test suite](https://github.com/karmi/tire/tree/master/test/integration)
15
+ and [issues](https://github.com/karmi/tire/issues).
12
16
 
13
17
  Installation
14
18
  ------------
15
19
 
16
- First, you need a running _ElasticSearch_ server. Thankfully, it's easy. Let's define easy:
20
+ OK. First, you need a running _ElasticSearch_ server. Thankfully, it's easy. Let's define easy:
17
21
 
18
- $ curl -k -L -o elasticsearch-0.16.0.tar.gz http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.16.0.tar.gz
19
- $ tar -zxvf elasticsearch-0.16.0.tar.gz
20
- $ ./elasticsearch-0.16.0/bin/elasticsearch -f
22
+ $ curl -k -L -o elasticsearch-0.17.2.tar.gz http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.17.2.tar.gz
23
+ $ tar -zxvf elasticsearch-0.17.2.tar.gz
24
+ $ ./elasticsearch-0.17.2/bin/elasticsearch -f
21
25
 
22
- OK. Easy. On a Mac, you can also use _Homebrew_:
26
+ See, easy. On a Mac, you can also use _Homebrew_:
23
27
 
24
28
  $ brew install elasticsearch
25
29
 
26
- OK. Let's install the gem via Rubygems:
30
+ Now, let's install the gem via Rubygems:
27
31
 
28
32
  $ gem install tire
29
33
 
@@ -39,8 +43,7 @@ Usage
39
43
 
40
44
  _Tire_ exposes easy-to-use domain specific language for fluent communication with _ElasticSearch_.
41
45
 
42
- It also blends with your [ActiveModel](https://github.com/rails/rails/tree/master/activemodel)
43
- classes for convenient usage in Rails applications.
46
+ It easily blends with your _ActiveModel_/_ActiveRecord_ classes for convenient usage in _Rails_ applications.
44
47
 
45
48
  To test-drive the core _ElasticSearch_ functionality, let's require the gem:
46
49
 
@@ -61,7 +64,7 @@ which allows you to use your preferred JSON library. We'll use the
61
64
  require 'yajl/json_gem'
62
65
  ```
63
66
 
64
- OK. Let's create an index named `articles` and store/index some documents:
67
+ Let's create an index named `articles` and store/index some documents:
65
68
 
66
69
  ```ruby
67
70
  Tire.index 'articles' do
@@ -83,6 +86,8 @@ for a specific document type:
83
86
 
84
87
  ```ruby
85
88
  Tire.index 'articles' do
89
+ delete
90
+
86
91
  create :mappings => {
87
92
  :article => {
88
93
  :properties => {
@@ -97,29 +102,35 @@ for a specific document type:
97
102
  ```
98
103
 
99
104
  Of course, we may have large amounts of data, and it may be impossible or impractical to add them to the index
100
- one by one. We can use _ElasticSearch's_ [bulk storage](http://www.elasticsearch.org/guide/reference/api/bulk.html):
105
+ one by one. We can use _ElasticSearch's_
106
+ [bulk storage](http://www.elasticsearch.org/guide/reference/api/bulk.html).
107
+ Notice, that collection items must have an `id` property or method,
108
+ and should have a `type` property, if you've set any specific mapping for the index.
101
109
 
102
110
  ```ruby
103
111
  articles = [
104
- { :id => '1', :title => 'one' },
105
- { :id => '2', :title => 'two' },
106
- { :id => '3', :title => 'three' }
112
+ { :id => '1', :type => 'article', :title => 'one', :tags => ['ruby'] },
113
+ { :id => '2', :type => 'article', :title => 'two', :tags => ['ruby', 'python'] },
114
+ { :id => '3', :type => 'article', :title => 'three', :tags => ['java'] },
115
+ { :id => '4', :type => 'article', :title => 'four', :tags => ['ruby', 'php'] }
107
116
  ]
108
117
 
109
- Tire.index 'bulk' do
118
+ Tire.index 'articles' do
110
119
  import articles
111
120
  end
112
121
  ```
113
122
 
114
- We can also easily manipulate the documents before storing them in the index, by passing a block to the
115
- `import` method:
123
+ We can easily manipulate the documents before storing them in the index, by passing a block to the
124
+ `import` method, like this:
116
125
 
117
126
  ```ruby
118
- Tire.index 'bulk' do
127
+ Tire.index 'articles' do
119
128
  import articles do |documents|
120
129
 
121
130
  documents.each { |document| document[:title].capitalize! }
122
131
  end
132
+
133
+ refresh
123
134
  end
124
135
  ```
125
136
 
@@ -137,7 +148,7 @@ from the database:
137
148
 
138
149
  filter :terms, :tags => ['ruby']
139
150
 
140
- sort { title 'desc' }
151
+ sort { by :title, 'desc' }
141
152
 
142
153
  facet 'global-tags' do
143
154
  terms :tags, :global => true
@@ -189,7 +200,7 @@ count for articles tagged 'php' is excluded, since they don't match the current
189
200
  # java 1
190
201
  ```
191
202
 
192
- Notice, that only variables from the enclosing scope are accesible.
203
+ Notice, that only variables from the enclosing scope are accessible.
193
204
  If we want to access the variables or methods from outer scope,
194
205
  we have to use a slight variation of the DSL, by passing the
195
206
  `search` and `query` objects around.
@@ -210,7 +221,7 @@ we can use the [_bool_](http://www.elasticsearch.org/guide/reference/query-dsl/b
210
221
  query. In _Tire_, we build them declaratively.
211
222
 
212
223
  ```ruby
213
- Tire.search('articles') do
224
+ Tire.search 'articles' do
214
225
  query do
215
226
  boolean do
216
227
  should { string 'tags:ruby' }
@@ -242,7 +253,7 @@ And a query for the _published_on_ property:
242
253
  Now, we can combine these queries for different searches:
243
254
 
244
255
  ```ruby
245
- Tire.search('articles') do
256
+ Tire.search 'articles' do
246
257
  query do
247
258
  boolean &tags_query
248
259
  boolean &published_on_query
@@ -250,7 +261,17 @@ Now, we can combine these queries for different searches:
250
261
  end
251
262
  ```
252
263
 
253
- If configuring the search payload with blocks somehow feels too weak for you, you can pass
264
+ Note, that you can pass options for configuring queries, facets, etc. by passing a Hash as the last argument to the method call:
265
+
266
+ ```ruby
267
+ Tire.search 'articles' do
268
+ query do
269
+ string 'ruby python', :default_operator => 'AND', :use_dis_max => true
270
+ end
271
+ end
272
+ ```
273
+
274
+ If configuring the search payload with blocks feels somehow too weak for you, you can pass
254
275
  a plain old Ruby `Hash` (or JSON string) with the query declaration to the `search` method:
255
276
 
256
277
  ```ruby
@@ -260,7 +281,7 @@ a plain old Ruby `Hash` (or JSON string) with the query declaration to the `sear
260
281
  If this sounds like a great idea to you, you are probably able to write your application
261
282
  using just `curl`, `sed` and `awk`.
262
283
 
263
- We can display the full query JSON for close inspection:
284
+ For debugging purposes, we can display the full query JSON for close inspection:
264
285
 
265
286
  ```ruby
266
287
  puts s.to_json
@@ -293,13 +314,14 @@ The _Tire_ DSL tries hard to provide a strong Ruby-like API for the main _Elasti
293
314
 
294
315
  By default, _Tire_ wraps the results collection in a enumerable `Results::Collection` class,
295
316
  and result items in a `Results::Item` class, which looks like a child of `Hash` and `Openstruct`,
296
- for smooth iterating and displaying the results.
317
+ for smooth iterating over and displaying the results.
297
318
 
298
319
  You may wrap the result items in your own class by setting the `Tire.configuration.wrapper`
299
320
  property. Your class must take a `Hash` of attributes on initialization.
300
321
 
301
- If that seems like a great idea to you, there's a big chance you already have such class, and one would bet
302
- it's an `ActiveRecord` or `ActiveModel` class, containing model of your Rails application.
322
+ If that seems like a great idea to you, there's a big chance you already have such class.
323
+
324
+ One would bet it's an `ActiveRecord` or `ActiveModel` class, containing model of your Rails application.
303
325
 
304
326
  Fortunately, _Tire_ makes blending _ElasticSearch_ features into your models trivially possible.
305
327
 
@@ -308,12 +330,15 @@ ActiveModel Integration
308
330
  -----------------------
309
331
 
310
332
  If you're the type with no time for lengthy introductions, you can generate a fully working
311
- example Rails application, with an `ActiveRecord` model and a search form, to play with:
333
+ example Rails application, with an `ActiveRecord` model and a search form, to play with
334
+ (it even downloads _ElasticSearch_ itself, generates the application skeleton and leaves you with
335
+ a _Git_ repository to explore the steps and the code):
312
336
 
313
337
  $ rails new searchapp -m https://github.com/karmi/tire/raw/master/examples/rails-application-template.rb
314
338
 
315
- For the rest, let's suppose you have an `Article` class in your Rails application.
316
- To make it searchable with _Tire_, you just `include` it:
339
+ For the rest of us, let's suppose you have an `Article` class in your _Rails_ application.
340
+
341
+ To make it searchable with _Tire_, just `include` it:
317
342
 
318
343
  ```ruby
319
344
  class Article < ActiveRecord::Base
@@ -333,8 +358,8 @@ When you now save a record:
333
358
 
334
359
  it is automatically added into the index, because of the included callbacks.
335
360
  (You may want to skip them in special cases, like when your records are indexed via some external
336
- mechanism, let's say CouchDB or RabbitMQ [river](http://www.elasticsearch.org/blog/2010/09/28/the_river.html)
337
- for _ElasticSearch_.)
361
+ mechanism, let's say a _CouchDB_ or _RabbitMQ_
362
+ [river](http://www.elasticsearch.org/blog/2010/09/28/the_river.html).
338
363
 
339
364
  The document attributes are indexed exactly as when you call the `Article#to_json` method.
340
365
 
@@ -344,22 +369,21 @@ Now you can search the records:
344
369
  Article.search 'love'
345
370
  ```
346
371
 
347
- OK. This is where the game stops, often. Not here.
372
+ OK. This is where the search game stops, often. Not here.
348
373
 
349
374
  First of all, you may use the full query DSL, as explained above, with filters, sorting,
350
375
  advanced facet aggregation, highlighting, etc:
351
376
 
352
377
  ```ruby
353
- q = 'love'
354
378
  Article.search do
355
- query { string q }
356
- facet('timeline') { date :published_on, :interval => 'month' }
357
- sort { published_on 'desc' }
379
+ query { string 'love' }
380
+ facet('timeline') { date :published_on, :interval => 'month' }
381
+ sort { by :published_on, 'desc' }
358
382
  end
359
383
  ```
360
384
 
361
- Dynamic mapping is a godsend when you're prototyping.
362
- For serious usage, though, you'll definitely want to define a custom mapping for your model:
385
+ Second, dynamic mapping is a godsend when you're prototyping.
386
+ For serious usage, though, you'll definitely want to define a custom mapping for your models:
363
387
 
364
388
  ```ruby
365
389
  class Article < ActiveRecord::Base
@@ -367,7 +391,7 @@ For serious usage, though, you'll definitely want to define a custom mapping for
367
391
  include Tire::Model::Callbacks
368
392
 
369
393
  mapping do
370
- indexes :id, :type => 'string', :analyzed => false
394
+ indexes :id, :type => 'string', :index => :not_analyzed
371
395
  indexes :title, :type => 'string', :analyzer => 'snowball', :boost => 100
372
396
  indexes :content, :type => 'string', :analyzer => 'snowball'
373
397
  indexes :author, :type => 'string', :analyzer => 'keyword'
@@ -376,10 +400,13 @@ For serious usage, though, you'll definitely want to define a custom mapping for
376
400
  end
377
401
  ```
378
402
 
379
- In this case, _only_ the defined model attributes are indexed when adding to the index.
403
+ In this case, _only_ the defined model attributes are indexed. The `mapping` declaration creates the
404
+ index when the class is loaded or when the importing features are used, and _only_ when it does not yet exist.
405
+ (It may well be reasonable to wrap the index creation logic in a class method of your model, so you
406
+ have better control on index creation when bootstrapping your application or when setting up the test suite.)
380
407
 
381
- When you want tight grip on how your model attributes are added to the index, just
382
- provide the `to_indexed_json` method yourself:
408
+ When you want a tight grip on how the attributes are added to the index, just
409
+ implement the `to_indexed_json` method in your model:
383
410
 
384
411
  ```ruby
385
412
  class Article < ActiveRecord::Base
@@ -404,24 +431,66 @@ provide the `to_indexed_json` method yourself:
404
431
  end
405
432
  ```
406
433
 
407
- Note that _Tire_-enhanced models are fully compatible with [`will_paginate`](https://github.com/mislav/will_paginate),
408
- so you can pass any parameters to the `search` method in the controller, as usual:
434
+ The results returned by `Article.search` are wrapped in the aforementioned `Item` class, by default.
435
+ This way, we have a fast and flexible access to the properties returned from _ElasticSearch_ (via the
436
+ `_source` or `fields` JSON properties). This way, we can index whatever JSON we like in _ElasticSearch_,
437
+ and retrieve it, simply, via the dot notation:
438
+
439
+ ```ruby
440
+ articles = Article.search 'love'
441
+ articles.each do |article|
442
+ puts article.title
443
+ puts article.author.last_name
444
+ end
445
+ ```
446
+
447
+ The `Item` instances masquerade themselves as instances of your model within a _Rails_ application
448
+ (based on the `_type` property retrieved from _ElasticSearch_), so you can use them carefree;
449
+ all the `url_for` or `dom_id` helpers work as expected.
450
+
451
+ If you need to access the “real” model (eg. to access its assocations or methods not
452
+ stored in _ElasticSearch_), just load it from the database:
453
+
454
+ ```ruby
455
+ puts article.load(:include => 'comments').comments.size
456
+ ```
457
+
458
+ You can see that _Tire_ stays as far from the database as possible. That's because it believes
459
+ you have most of the data you want to display stored in _ElasticSearch_. When you need
460
+ to eagerly load the records from the database itself, for whatever reason,
461
+ you can do it with the `:load` option when searching:
462
+
463
+ ```ruby
464
+ # Will call `Article.search [1, 2, 3]`
465
+ Article.search 'love', :load => true
466
+ ```
467
+
468
+ Instead of simple `true`, you can pass any options for the model's find method:
469
+
470
+ ```ruby
471
+ # Will call `Article.search [1, 2, 3], :include => 'comments'`
472
+ Article.search :load => { :include => 'comments' } do
473
+ query { string 'love' }
474
+ end
475
+ ```
476
+
477
+ Note that _Tire_ search results are fully compatible with [`will_paginate`](https://github.com/mislav/will_paginate),
478
+ so you can pass all the usual parameters to the `search` method in the controller:
409
479
 
410
480
  ```ruby
411
481
  @articles = Article.search params[:q], :page => (params[:page] || 1)
412
482
  ```
413
483
 
414
- OK. Chances are, you have lots of records stored in the underlying database. How will you get them to _ElasticSearch_? Easy:
484
+ OK. Chances are, you have lots of records stored in your database. How will you get them to _ElasticSearch_? Easy:
415
485
 
416
486
  ```ruby
417
487
  Article.elasticsearch_index.import Article.all
418
488
  ```
419
489
 
420
- However, this way, all your records are loaded into memory, serialized into JSON,
490
+ This way, however, all your records are loaded into memory, serialized into JSON,
421
491
  and sent down the wire to _ElasticSearch_. Not practical, you say? You're right.
422
492
 
423
- Provided your model implements some sort of _pagination_ — and it probably does, for so much data —,
424
- you can just run:
493
+ Provided your model implements some sort of _pagination_ — and it probably does —, you can just run:
425
494
 
426
495
  ```ruby
427
496
  Article.import
@@ -453,14 +522,14 @@ provided by the `mapping` block in your model):
453
522
  When you'll spend more time with _ElasticSearch_, you'll notice how
454
523
  [index aliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html)
455
524
  are the best idea since the invention of inverted index.
456
- You can index your data into a fresh index (and possibly update an alias if everything's fine):
525
+ You can index your data into a fresh index (and possibly update an alias once everything's fine):
457
526
 
458
527
  ```bash
459
528
  $ rake environment tire:import CLASS='Article' INDEX='articles-2011-05'
460
529
  ```
461
530
 
462
531
  OK. All this time we have been talking about `ActiveRecord` models, since
463
- it is a reasonable Rails' default for the storage layer.
532
+ it is a reasonable _Rails_' default for the storage layer.
464
533
 
465
534
  But what if you use another database such as [MongoDB](http://www.mongodb.org/),
466
535
  another object mapping library, such as [Mongoid](http://mongoid.org/)?
@@ -494,12 +563,10 @@ Well, things stay mostly the same:
494
563
  Article.search 'love'
495
564
  ```
496
565
 
497
- That's kinda nice. But there's more.
566
+ _Tire_ does not care what's your primary data storage solution, if it has an _ActiveModel_-compatible
567
+ adapter. But there's more.
498
568
 
499
- _Tire_ implements not only _searchable_ features, but also _persistence_ features.
500
-
501
- This means that you can use a _Tire_ model **instead of** your database, not just
502
- for searching your database. Why would you like to do that?
569
+ _Tire_ implements not only _searchable_ features, but also _persistence_ features. This means you can use a _Tire_ model **instead of your database**, not just for _searching_ your database. Why would you like to do that?
503
570
 
504
571
  Well, because you're tired of database migrations and lots of hand-holding with your
505
572
  database to store stuff like `{ :name => 'Tire', :tags => [ 'ruby', 'search' ] }`.
@@ -510,8 +577,7 @@ then constructing elaborate database query conditions.
510
577
  Because you have _lots_ of data and want to use _ElasticSearch's_
511
578
  advanced distributed features.
512
579
 
513
- To use the persistence features, you have to include the `Tire::Persistence` module
514
- in your class and define the properties (analogous to the way you do with CouchDB- or MongoDB-based models):
580
+ To use the persistence features, just include the `Tire::Persistence` module in your class and define the properties (like with _CouchDB_- or _MongoDB_-based models):
515
581
 
516
582
  ```ruby
517
583
  class Article
@@ -532,6 +598,9 @@ Of course, not all validations or `ActionPack` helpers will be available to your
532
598
  but if you can live with that, you've just got a schema-free, highly-scalable storage
533
599
  and retrieval engine for your data.
534
600
 
601
+ Please be sure to peruse the [integration test suite](https://github.com/karmi/tire/tree/master/test/integration)
602
+ for examples of the API and _ActiveModel_ integration usage.
603
+
535
604
  Todo, Plans & Ideas
536
605
  -------------------
537
606
 
@@ -106,7 +106,7 @@ say_status "Rubygems", "Adding Rubygems into Gemfile...\n", :yellow
106
106
  puts '-'*80, ''; sleep 1
107
107
 
108
108
  gem 'tire'
109
- gem 'will_paginate', '~>3.0.pre'
109
+ gem 'will_paginate', '~> 3.0'
110
110
 
111
111
  git :add => '.'
112
112
  git :commit => "-m 'Added gems'"
@@ -43,9 +43,9 @@ require 'tire'
43
43
 
44
44
  [ERROR] You don’t appear to have ElasticSearch installed. Please install and launch it with the following commands:
45
45
 
46
- curl -k -L -o elasticsearch-0.16.0.tar.gz http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.16.0.tar.gz
47
- tar -zxvf elasticsearch-0.16.0.tar.gz
48
- ./elasticsearch-0.16.0/bin/elasticsearch -f
46
+ curl -k -L -o elasticsearch-0.17.2.tar.gz http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.17.2.tar.gz
47
+ tar -zxvf elasticsearch-0.17.2.tar.gz
48
+ ./elasticsearch-0.17.2/bin/elasticsearch -f
49
49
  INSTALL
50
50
 
51
51
  ### Storing and indexing documents
@@ -667,7 +667,7 @@ s = Tire.search 'articles' do
667
667
 
668
668
  # ... but will sort them by their `title`, in descending order.
669
669
  #
670
- sort { title 'desc' }
670
+ sort { by :title, 'desc' }
671
671
  end
672
672
 
673
673
  # The results:
@@ -692,11 +692,11 @@ s = Tire.search 'articles' do
692
692
 
693
693
  # We will sort the results by their `published_on` property in _ascending_ order (the default),
694
694
  #
695
- published_on
695
+ by :published_on
696
696
 
697
697
  # and by their `title` property, in _descending_ order.
698
698
  #
699
- title 'desc'
699
+ by :title 'desc'
700
700
  end
701
701
  end
702
702
 
@@ -41,21 +41,8 @@ module Tire
41
41
  end
42
42
 
43
43
  def store(*args)
44
- case
45
- when ( args.size === 3 && (args.first.is_a?(String) || args.first.is_a?(Symbol)) )
46
- Tire.warn "Passing the document type as argument in Index#store has been deprecated, " +
47
- "please pass a Hash with _type/type property, or " +
48
- "an object with _type/type/document_type method."
49
- type, document, options = args
50
- when ( args.size === 2 && (args.first.is_a?(String) || args.first.is_a?(Symbol)) )
51
- Tire.warn "Passing the document type as argument in Index#store has been deprecated" +
52
- "please pass a Hash with _type/type property, or " +
53
- "an object with _type/type/document_type method."
54
- type, document = args
55
- else
56
- document, options = args
57
- type = get_type_from_document(document)
58
- end
44
+ document, options = args
45
+ type = get_type_from_document(document)
59
46
 
60
47
  if options
61
48
  percolate = options[:percolate]
@@ -118,7 +105,7 @@ module Tire
118
105
  when method
119
106
  options = {:page => 1, :per_page => 1000}.merge options
120
107
  while documents = klass_or_collection.send(method.to_sym, options.merge(:page => options[:page])) \
121
- and documents.size > 0
108
+ and not documents.empty?
122
109
  documents = yield documents if block_given?
123
110
 
124
111
  bulk_store documents
@@ -218,15 +205,8 @@ module Tire
218
205
  end
219
206
 
220
207
  def percolate(*args, &block)
221
- if args.size > 1
222
- Tire.warn "Passing the document type as argument in Index#percolate has been deprecated, " +
223
- "please pass a Hash with _type/type property, or " +
224
- "an object with _type/type/document_type method."
225
- type, document = args
226
- else
227
- document = args.pop
228
- type = get_type_from_document(document)
229
- end
208
+ document = args.pop
209
+ type = get_type_from_document(document)
230
210
 
231
211
  document = MultiJson.decode convert_document_to_json(document)
232
212
 
@@ -273,14 +253,14 @@ module Tire
273
253
  when document.respond_to?(:document_type)
274
254
  document.document_type
275
255
  when document.is_a?(Hash)
276
- document.delete(:_type) || document.delete('_type') || document.delete(:type) || document.delete('type')
256
+ document[:_type] || document['_type'] || document[:type] || document['type']
277
257
  when document.respond_to?(:_type)
278
258
  document._type
279
259
  when document.respond_to?(:type) && document.type != document.class
280
260
  document.type
281
261
  end
282
262
  $VERBOSE = old_verbose
283
- type ||= :document
263
+ type || :document
284
264
  end
285
265
 
286
266
  def get_id_from_document(document)