1 /* 2 * ModeShape (http://www.modeshape.org) 3 * See the COPYRIGHT.txt file distributed with this work for information 4 * regarding copyright ownership. Some portions may be licensed 5 * to Red Hat, Inc. under one or more contributor license agreements. 6 * See the AUTHORS.txt file in the distribution for a full listing of 7 * individual contributors. 8 * 9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape 10 * is licensed to you under the terms of the GNU Lesser General Public License as 11 * published by the Free Software Foundation; either version 2.1 of 12 * the License, or (at your option) any later version. 13 * 14 * ModeShape is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this software; if not, write to the Free 21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 23 */ 24 package org.modeshape.search.lucene; 25 26 import java.math.BigDecimal; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.Map; 30 import net.jcip.annotations.Immutable; 31 import net.jcip.annotations.NotThreadSafe; 32 import org.apache.lucene.document.Field; 33 import org.apache.lucene.document.Field.Index; 34 import org.apache.lucene.document.Field.Store; 35 import org.modeshape.common.util.CheckArg; 36 import org.modeshape.graph.property.Name; 37 38 /** 39 * The set of rules that dictate how properties should be indexed. 40 */ 41 @Immutable 42 public class IndexRules { 43 44 public static enum FieldType { 45 STRING, 46 DOUBLE, 47 FLOAT, 48 INT, 49 BOOLEAN, 50 LONG, 51 DATE, 52 BINARY, 53 REFERENCE, 54 WEAK_REFERENCE, 55 DECIMAL; 56 } 57 58 /** 59 * A single rule that dictates how a single property should be indexed. 60 * 61 * @see IndexRules#getRule(Name) 62 */ 63 @Immutable 64 public static interface Rule { 65 66 boolean isSkipped(); 67 68 boolean canBeReference(); 69 70 boolean isFullTextSearchable(); 71 72 FieldType getType(); 73 74 Field.Store getStoreOption(); 75 76 Field.Index getIndexOption(); 77 } 78 79 @Immutable 80 public static interface NumericRule<T> extends Rule { 81 T getMinimum(); 82 83 T getMaximum(); 84 } 85 86 public static final Rule SKIP = new SkipRule(); 87 88 @Immutable 89 protected static class SkipRule implements Rule { 90 91 /** 92 * {@inheritDoc} 93 * 94 * @see Rule#getType() 95 */ 96 public FieldType getType() { 97 return FieldType.STRING; 98 } 99 100 /** 101 * {@inheritDoc} 102 * 103 * @see Rule#isSkipped() 104 */ 105 public boolean isSkipped() { 106 return true; 107 } 108 109 /** 110 * {@inheritDoc} 111 * 112 * @see org.modeshape.search.lucene.IndexRules.Rule#isFullTextSearchable() 113 */ 114 @Override 115 public boolean isFullTextSearchable() { 116 return false; 117 } 118 119 /** 120 * {@inheritDoc} 121 * 122 * @see org.modeshape.search.lucene.IndexRules.Rule#canBeReference() 123 */ 124 @Override 125 public boolean canBeReference() { 126 return false; 127 } 128 129 /** 130 * {@inheritDoc} 131 * 132 * @see Rule#getIndexOption() 133 */ 134 public Index getIndexOption() { 135 return Field.Index.NO; 136 } 137 138 /** 139 * {@inheritDoc} 140 * 141 * @see Rule#getStoreOption() 142 */ 143 public Store getStoreOption() { 144 return Field.Store.NO; 145 } 146 } 147 148 @Immutable 149 protected static class TypedRule implements Rule { 150 protected final boolean canBeReference; 151 protected final boolean fullTextSearchable; 152 protected final FieldType type; 153 protected final Field.Store store; 154 protected final Field.Index index; 155 156 protected TypedRule( FieldType type, 157 Field.Store store, 158 Field.Index index, 159 boolean canBeReference, 160 boolean fullTextSearchable ) { 161 this.type = type; 162 this.index = index; 163 this.store = store; 164 this.canBeReference = canBeReference; 165 this.fullTextSearchable = fullTextSearchable; 166 assert this.type != null; 167 assert this.index != null; 168 assert this.store != null; 169 } 170 171 /** 172 * {@inheritDoc} 173 * 174 * @see IndexRules.Rule#getType() 175 */ 176 public FieldType getType() { 177 return type; 178 } 179 180 /** 181 * {@inheritDoc} 182 * 183 * @see IndexRules.Rule#isSkipped() 184 */ 185 public boolean isSkipped() { 186 return false; 187 } 188 189 /** 190 * {@inheritDoc} 191 * 192 * @see org.modeshape.search.lucene.IndexRules.Rule#isFullTextSearchable() 193 */ 194 @Override 195 public boolean isFullTextSearchable() { 196 return fullTextSearchable; 197 } 198 199 /** 200 * {@inheritDoc} 201 * 202 * @see org.modeshape.search.lucene.IndexRules.Rule#canBeReference() 203 */ 204 @Override 205 public boolean canBeReference() { 206 return canBeReference; 207 } 208 209 /** 210 * {@inheritDoc} 211 * 212 * @see IndexRules.Rule#getIndexOption() 213 */ 214 public Index getIndexOption() { 215 return index; 216 } 217 218 /** 219 * {@inheritDoc} 220 * 221 * @see IndexRules.Rule#getStoreOption() 222 */ 223 public Store getStoreOption() { 224 return store; 225 } 226 227 /** 228 * {@inheritDoc} 229 * 230 * @see java.lang.Object#toString() 231 */ 232 @Override 233 public String toString() { 234 return type.name() + " rule (" + store + "," + index + ")"; 235 } 236 } 237 238 @Immutable 239 protected static class NumericTypedRule<T> extends TypedRule implements NumericRule<T> { 240 protected final T minValue; 241 protected final T maxValue; 242 243 protected NumericTypedRule( FieldType type, 244 Field.Store store, 245 Field.Index index, 246 T minValue, 247 T maxValue ) { 248 super(type, store, index, false, false); 249 this.minValue = minValue; 250 this.maxValue = maxValue; 251 assert this.minValue != null; 252 assert this.maxValue != null; 253 } 254 255 /** 256 * {@inheritDoc} 257 * 258 * @see IndexRules.NumericRule#getMaximum() 259 */ 260 public T getMaximum() { 261 return maxValue; 262 } 263 264 /** 265 * {@inheritDoc} 266 * 267 * @see IndexRules.NumericRule#getMinimum() 268 */ 269 public T getMinimum() { 270 return minValue; 271 } 272 273 /** 274 * {@inheritDoc} 275 * 276 * @see java.lang.Object#toString() 277 */ 278 @Override 279 public String toString() { 280 return super.toString() + " with range [" + minValue + "," + maxValue + "]"; 281 } 282 } 283 284 private final Map<Name, Rule> rulesByName; 285 private final Rule defaultRule; 286 287 protected IndexRules( Map<Name, Rule> rulesByName, 288 Rule defaultRule ) { 289 this.rulesByName = rulesByName; 290 this.defaultRule = defaultRule != null ? defaultRule : SKIP; 291 assert this.defaultRule != null; 292 } 293 294 /** 295 * Get the rule associated with the given property name. 296 * 297 * @param name the property name, or null if the default rule is to be returned 298 * @return the rule; never null 299 */ 300 public Rule getRule( Name name ) { 301 Rule result = rulesByName.get(name); 302 return result != null ? result : this.defaultRule; 303 } 304 305 /** 306 * Return a new builder that can be used to create {@link IndexRules} objects. 307 * 308 * @return a builder; never null 309 */ 310 public static Builder createBuilder() { 311 return new Builder(new HashMap<Name, Rule>(), null); 312 } 313 314 /** 315 * Return a new builder that can be used to create {@link IndexRules} objects. 316 * 317 * @param initialRules the rules that the builder should start with 318 * @return a builder; never null 319 * @throws IllegalArgumentException if the initial rules reference is null 320 */ 321 public static Builder createBuilder( IndexRules initialRules ) { 322 CheckArg.isNotNull(initialRules, "initialRules"); 323 return new Builder(new HashMap<Name, Rule>(initialRules.rulesByName), initialRules.defaultRule); 324 } 325 326 /** 327 * A builder of immutable {@link IndexRules} objects. 328 */ 329 @NotThreadSafe 330 public static class Builder { 331 private final Map<Name, Rule> rulesByName; 332 private Rule defaultRule; 333 334 Builder( Map<Name, Rule> rulesByName, 335 Rule defaultRule ) { 336 assert rulesByName != null; 337 this.rulesByName = rulesByName; 338 this.defaultRule = defaultRule; 339 } 340 341 /** 342 * Mark the properties with the supplied names to be skipped from indexing. 343 * 344 * @param namesToIndex the names of the properties that are to be skipped 345 * @return this builder for convenience and method chaining; never null 346 */ 347 public Builder skip( Name... namesToIndex ) { 348 if (namesToIndex != null) { 349 for (Name name : namesToIndex) { 350 rulesByName.put(name, SKIP); 351 } 352 } 353 return this; 354 } 355 356 /** 357 * Define a string-based field as the default. 358 * 359 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 360 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 361 * @param canBeReference true if this field can contain references; or false if it cannot 362 * @param fullTextSearchable true if this field is full-text searchable, or false otherwise 363 * @return this builder for convenience and method chaining; never null 364 */ 365 public Builder defaultTo( Field.Store store, 366 Field.Index index, 367 boolean canBeReference, 368 boolean fullTextSearchable ) { 369 if (store == null) store = Field.Store.YES; 370 if (index == null) index = Field.Index.NOT_ANALYZED; 371 defaultRule = new TypedRule(FieldType.STRING, store, index, canBeReference, fullTextSearchable); 372 return this; 373 } 374 375 /** 376 * Define a string-based field in the indexes. This method will overwrite any existing definition in this builder. 377 * 378 * @param name the name of the field 379 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 380 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 381 * @param canBeReference true if this field can contain references; or false if it cannot 382 * @param fullTextSearchable true if this field is full-text searchable, or false otherwise 383 * @return this builder for convenience and method chaining; never null 384 */ 385 public Builder stringField( Name name, 386 Field.Store store, 387 Field.Index index, 388 boolean canBeReference, 389 boolean fullTextSearchable ) { 390 if (store == null) store = Field.Store.YES; 391 if (index == null) index = Field.Index.NOT_ANALYZED; 392 Rule rule = new TypedRule(FieldType.STRING, store, index, canBeReference, fullTextSearchable); 393 rulesByName.put(name, rule); 394 return this; 395 } 396 397 /** 398 * Define a binary-based field in the indexes. This method will overwrite any existing definition in this builder. 399 * 400 * @param name the name of the field 401 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 402 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 403 * @param fullTextSearchable true if this field is full-text searchable, or false otherwise 404 * @return this builder for convenience and method chaining; never null 405 */ 406 public Builder binaryField( Name name, 407 Field.Store store, 408 Field.Index index, 409 boolean fullTextSearchable ) { 410 if (store == null) store = Field.Store.YES; 411 if (index == null) index = Field.Index.NOT_ANALYZED; 412 Rule rule = new TypedRule(FieldType.BINARY, store, index, false, fullTextSearchable); 413 rulesByName.put(name, rule); 414 return this; 415 } 416 417 /** 418 * Define a reference-based field in the indexes. This method will overwrite any existing definition in this builder. 419 * 420 * @param name the name of the field 421 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 422 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 423 * @return this builder for convenience and method chaining; never null 424 */ 425 public Builder referenceField( Name name, 426 Field.Store store, 427 Field.Index index ) { 428 if (store == null) store = Field.Store.YES; 429 if (index == null) index = Field.Index.NOT_ANALYZED; 430 Rule rule = new TypedRule(FieldType.REFERENCE, store, index, true, false); 431 rulesByName.put(name, rule); 432 return this; 433 } 434 435 /** 436 * Define a weak-reference-based field in the indexes. This method will overwrite any existing definition in this builder. 437 * 438 * @param name the name of the field 439 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 440 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 441 * @param fullTextSearchable true if this field is full-text searchable, or false otherwise 442 * @return this builder for convenience and method chaining; never null 443 */ 444 public Builder weakReferenceField( Name name, 445 Field.Store store, 446 Field.Index index, 447 boolean fullTextSearchable ) { 448 if (store == null) store = Field.Store.YES; 449 if (index == null) index = Field.Index.NOT_ANALYZED; 450 Rule rule = new TypedRule(FieldType.WEAK_REFERENCE, store, index, false, fullTextSearchable); 451 rulesByName.put(name, rule); 452 return this; 453 } 454 455 protected <T> Builder numericField( Name name, 456 FieldType type, 457 Field.Store store, 458 Field.Index index, 459 T minValue, 460 T maxValue ) { 461 if (store == null) store = Field.Store.YES; 462 if (index == null) index = Field.Index.NOT_ANALYZED; 463 Rule rule = new NumericTypedRule<T>(type, store, index, minValue, maxValue); 464 rulesByName.put(name, rule); 465 return this; 466 } 467 468 /** 469 * Define a boolean-based field in the indexes. This method will overwrite any existing definition in this builder. 470 * 471 * @param name the name of the field 472 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 473 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 474 * @return this builder for convenience and method chaining; never null 475 */ 476 public Builder booleanField( Name name, 477 Field.Store store, 478 Field.Index index ) { 479 return numericField(name, FieldType.BOOLEAN, store, index, Boolean.FALSE, Boolean.TRUE); 480 } 481 482 /** 483 * Define a integer-based field in the indexes. This method will overwrite any existing definition in this builder. 484 * 485 * @param name the name of the field 486 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 487 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 488 * @param minValue the minimum value for this field, or null if there is no minimum value 489 * @param maxValue the maximum value for this field, or null if there is no maximum value 490 * @return this builder for convenience and method chaining; never null 491 */ 492 public Builder integerField( Name name, 493 Field.Store store, 494 Field.Index index, 495 Integer minValue, 496 Integer maxValue ) { 497 if (minValue == null) minValue = Integer.MIN_VALUE; 498 if (maxValue == null) maxValue = Integer.MAX_VALUE; 499 return numericField(name, FieldType.INT, store, index, minValue, maxValue); 500 } 501 502 /** 503 * Define a long-based field in the indexes. This method will overwrite any existing definition in this builder. 504 * 505 * @param name the name of the field 506 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 507 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 508 * @param minValue the minimum value for this field, or null if there is no minimum value 509 * @param maxValue the maximum value for this field, or null if there is no maximum value 510 * @return this builder for convenience and method chaining; never null 511 */ 512 public Builder longField( Name name, 513 Field.Store store, 514 Field.Index index, 515 Long minValue, 516 Long maxValue ) { 517 if (minValue == null) minValue = Long.MIN_VALUE; 518 if (maxValue == null) maxValue = Long.MAX_VALUE; 519 return numericField(name, FieldType.LONG, store, index, minValue, maxValue); 520 } 521 522 /** 523 * Define a decimal-based field in the indexes. This method will overwrite any existing definition in this builder. 524 * <p> 525 * Decimal fields can contain an exceedingly large range of values, and because Lucene is not capable of performing range 526 * queries using BigDecimal values, decimal fields are stored as lexicographically-sortable strings. 527 * 528 * @param name the name of the field 529 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 530 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 531 * @param minValue the minimum value for this field, or null if there is no minimum value 532 * @param maxValue the maximum value for this field, or null if there is no maximum value 533 * @return this builder for convenience and method chaining; never null 534 */ 535 public Builder decimalField( Name name, 536 Field.Store store, 537 Field.Index index, 538 BigDecimal minValue, 539 BigDecimal maxValue ) { 540 if (store == null) store = Field.Store.YES; 541 if (index == null) index = Field.Index.NOT_ANALYZED; 542 Rule rule = new TypedRule(FieldType.STRING, store, index, false, false); 543 rulesByName.put(name, rule); 544 return this; 545 } 546 547 /** 548 * Define a date-based field in the indexes. This method will overwrite any existing definition in this builder. 549 * 550 * @param name the name of the field 551 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 552 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 553 * @param minValue the minimum value for this field, or null if there is no minimum value 554 * @param maxValue the maximum value for this field, or null if there is no maximum value 555 * @return this builder for convenience and method chaining; never null 556 */ 557 public Builder dateField( Name name, 558 Field.Store store, 559 Field.Index index, 560 Long minValue, 561 Long maxValue ) { 562 if (minValue == null) minValue = 0L; 563 if (maxValue == null) maxValue = Long.MAX_VALUE; 564 return numericField(name, FieldType.DATE, store, index, minValue, maxValue); 565 } 566 567 /** 568 * Define a float-based field in the indexes. This method will overwrite any existing definition in this builder. 569 * 570 * @param name the name of the field 571 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 572 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 573 * @param minValue the minimum value for this field, or null if there is no minimum value 574 * @param maxValue the maximum value for this field, or null if there is no maximum value 575 * @return this builder for convenience and method chaining; never null 576 */ 577 public Builder floatField( Name name, 578 Field.Store store, 579 Field.Index index, 580 Float minValue, 581 Float maxValue ) { 582 if (minValue == null) minValue = Float.MIN_VALUE; 583 if (maxValue == null) maxValue = Float.MAX_VALUE; 584 return numericField(name, FieldType.FLOAT, store, index, minValue, maxValue); 585 } 586 587 /** 588 * Define a double-based field in the indexes. This method will overwrite any existing definition in this builder. 589 * 590 * @param name the name of the field 591 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 592 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 593 * @param minValue the minimum value for this field, or null if there is no minimum value 594 * @param maxValue the maximum value for this field, or null if there is no maximum value 595 * @return this builder for convenience and method chaining; never null 596 */ 597 public Builder doubleField( Name name, 598 Field.Store store, 599 Field.Index index, 600 Double minValue, 601 Double maxValue ) { 602 if (minValue == null) minValue = Double.MIN_VALUE; 603 if (maxValue == null) maxValue = Double.MAX_VALUE; 604 return numericField(name, FieldType.DOUBLE, store, index, minValue, maxValue); 605 } 606 607 /** 608 * Define a integer-based field in the indexes. This method will overwrite any existing definition in this builder. 609 * 610 * @param name the name of the field 611 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 612 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 613 * @param minValue the minimum value for this field, or null if there is no minimum value 614 * @return this builder for convenience and method chaining; never null 615 */ 616 public Builder integerField( Name name, 617 Field.Store store, 618 Field.Index index, 619 Integer minValue ) { 620 return integerField(name, store, index, minValue, null); 621 } 622 623 /** 624 * Define a long-based field in the indexes. This method will overwrite any existing definition in this builder. 625 * 626 * @param name the name of the field 627 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 628 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 629 * @param minValue the minimum value for this field, or null if there is no minimum value 630 * @return this builder for convenience and method chaining; never null 631 */ 632 public Builder longField( Name name, 633 Field.Store store, 634 Field.Index index, 635 Long minValue ) { 636 return longField(name, store, index, minValue, null); 637 } 638 639 /** 640 * Define a date-based field in the indexes. This method will overwrite any existing definition in this builder. 641 * 642 * @param name the name of the field 643 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 644 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 645 * @param minValue the minimum value for this field, or null if there is no minimum value 646 * @return this builder for convenience and method chaining; never null 647 */ 648 public Builder dateField( Name name, 649 Field.Store store, 650 Field.Index index, 651 Long minValue ) { 652 return dateField(name, store, index, minValue, null); 653 } 654 655 /** 656 * Define a float-based field in the indexes. This method will overwrite any existing definition in this builder. 657 * 658 * @param name the name of the field 659 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 660 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 661 * @param minValue the minimum value for this field, or null if there is no minimum value 662 * @return this builder for convenience and method chaining; never null 663 */ 664 public Builder floatField( Name name, 665 Field.Store store, 666 Field.Index index, 667 Float minValue ) { 668 return floatField(name, store, index, minValue, null); 669 } 670 671 /** 672 * Define a double-based field in the indexes. This method will overwrite any existing definition in this builder. 673 * 674 * @param name the name of the field 675 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 676 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 677 * @param minValue the minimum value for this field, or null if there is no minimum value 678 * @return this builder for convenience and method chaining; never null 679 */ 680 public Builder doubleField( Name name, 681 Field.Store store, 682 Field.Index index, 683 Double minValue ) { 684 return doubleField(name, store, index, minValue, null); 685 } 686 687 /** 688 * Define a integer-based field in the indexes. This method will overwrite any existing definition in this builder. 689 * 690 * @param name the name of the field 691 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 692 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 693 * @return this builder for convenience and method chaining; never null 694 */ 695 public Builder integerField( Name name, 696 Field.Store store, 697 Field.Index index ) { 698 return integerField(name, store, index, null, null); 699 } 700 701 /** 702 * Define a long-based field in the indexes. This method will overwrite any existing definition in this builder. 703 * 704 * @param name the name of the field 705 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 706 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 707 * @return this builder for convenience and method chaining; never null 708 */ 709 public Builder longField( Name name, 710 Field.Store store, 711 Field.Index index ) { 712 return longField(name, store, index, null, null); 713 } 714 715 /** 716 * Define a date-based field in the indexes. This method will overwrite any existing definition in this builder. 717 * 718 * @param name the name of the field 719 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 720 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 721 * @return this builder for convenience and method chaining; never null 722 */ 723 public Builder dateField( Name name, 724 Field.Store store, 725 Field.Index index ) { 726 return dateField(name, store, index, null, null); 727 } 728 729 /** 730 * Define a float-based field in the indexes. This method will overwrite any existing definition in this builder. 731 * 732 * @param name the name of the field 733 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 734 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 735 * @return this builder for convenience and method chaining; never null 736 */ 737 public Builder floatField( Name name, 738 Field.Store store, 739 Field.Index index ) { 740 return floatField(name, store, index, null, null); 741 } 742 743 /** 744 * Define a double-based field in the indexes. This method will overwrite any existing definition in this builder. 745 * 746 * @param name the name of the field 747 * @param store the storage setting, or null if the field should be {@link Store#YES stored} 748 * @param index the index setting, or null if the field should be indexed but {@link Index#NOT_ANALYZED not analyzed} 749 * @return this builder for convenience and method chaining; never null 750 */ 751 public Builder doubleField( Name name, 752 Field.Store store, 753 Field.Index index ) { 754 return doubleField(name, store, index, null, null); 755 } 756 757 /** 758 * Build the indexing rules. 759 * 760 * @return the immutable indexing rules. 761 */ 762 public IndexRules build() { 763 return new IndexRules(Collections.unmodifiableMap(new HashMap<Name, Rule>(rulesByName)), defaultRule); 764 } 765 } 766 }