Skip to content

Commit 89843a1

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-1183 - Add support for Hashed Indexes.
We now support hashed index definitions via IndexOperations. Reading index information back allows to identify a hashed index via isHashed(). Original pull request: spring-projects#750.
1 parent e06f326 commit 89843a1

File tree

10 files changed

+435
-29
lines changed

10 files changed

+435
-29
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.index;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
22+
23+
/**
24+
* Marker interface for a property that should be used as key for a
25+
* <a href="https://docs.mongodb.com/manual/core/index-hashed/">Hashed Index</a>. If used on a simple property the index
26+
* uses a hashing function to compute the hash of the value of the index field. Added to a property of complex type the
27+
* embedded document is collapsed and the hash computed for the entire object.
28+
* <p />
29+
*
30+
* <pre>
31+
* <code>
32+
*
33+
* &#64;Document
34+
* public class DomainType {
35+
*
36+
* &#64;HashIndexed @Id String id;
37+
* }
38+
* </code>
39+
* </pre>
40+
*
41+
* {@link HashIndexed} can also be used as meta {@link java.lang.annotation.Annotation} to create composed annotations.
42+
*
43+
* <pre>
44+
* <code>
45+
*
46+
* &#64;Indexed
47+
* &#64;HashIndexed
48+
* &#64;Retention(RetentionPolicy.RUNTIME)
49+
* public @interface IndexAndHash {
50+
*
51+
* &#64;AliasFor(annotation = Indexed.class, attribute = "name")
52+
* String name() default "";
53+
* }
54+
*
55+
* &#64;Document
56+
* public class DomainType {
57+
*
58+
* &#64;ComposedHashIndexed(name = "idx-name") String value;
59+
* }
60+
* </code>
61+
* </pre>
62+
*
63+
* @author Christoph Strobl
64+
* @since 2.2
65+
* @see HashedIndex
66+
*/
67+
@Target({ ElementType.ANNOTATION_TYPE, ElementType.FIELD })
68+
@Retention(RetentionPolicy.RUNTIME)
69+
public @interface HashIndexed {
70+
71+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.core.index;
17+
18+
import org.bson.Document;
19+
import org.springframework.util.Assert;
20+
21+
/**
22+
* {@link IndexDefinition} implementation for MongoDB
23+
* <a href="https://docs.mongodb.com/manual/core/index-hashed/">Hashed Indexes</a> maintaining entries with hashes of
24+
* the values of the indexed field.
25+
*
26+
* @author Christoph Strobl
27+
* @since 2.2
28+
*/
29+
public class HashedIndex implements IndexDefinition {
30+
31+
private final String field;
32+
33+
private HashedIndex(String field) {
34+
35+
Assert.hasText(field, "Field must not be null nor empty!");
36+
this.field = field;
37+
}
38+
39+
/**
40+
* Creates a new {@link HashedIndex} for the given field.
41+
*
42+
* @param field must not be {@literal null} nor empty.
43+
* @return
44+
*/
45+
public static HashedIndex hashed(String field) {
46+
return new HashedIndex(field);
47+
}
48+
49+
/*
50+
* (non-Javadoc)
51+
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexKeys()
52+
*/
53+
@Override
54+
public Document getIndexKeys() {
55+
return new Document(field, "hashed");
56+
}
57+
58+
/*
59+
* (non-Javadoc)
60+
* @see org.springframework.data.mongodb.core.index.IndexDefinition#getIndexOptions()
61+
*/
62+
@Override
63+
public Document getIndexOptions() {
64+
return new Document();
65+
}
66+
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexField.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
public final class IndexField {
3131

3232
enum Type {
33-
GEO, TEXT, DEFAULT;
33+
GEO, TEXT, DEFAULT, HASH;
3434
}
3535

3636
private final String key;
@@ -49,7 +49,9 @@ private IndexField(String key, @Nullable Direction direction, @Nullable Type typ
4949
if (Type.GEO.equals(type) || Type.TEXT.equals(type)) {
5050
Assert.isNull(direction, "Geo/Text indexes must not have a direction!");
5151
} else {
52-
Assert.notNull(direction, "Default indexes require a direction");
52+
if (!Type.HASH.equals(type)) {
53+
Assert.notNull(direction, "Default indexes require a direction");
54+
}
5355
}
5456

5557
this.key = key;
@@ -65,6 +67,17 @@ public static IndexField create(String key, Direction order) {
6567
return new IndexField(key, order, Type.DEFAULT);
6668
}
6769

70+
/**
71+
* Creates a {@literal hashed} {@link IndexField} for the given key.
72+
*
73+
* @param key must not be {@literal null} or empty.
74+
* @return new instance of {@link IndexField}.
75+
* @since 2.2
76+
*/
77+
static IndexField hashed(String key) {
78+
return new IndexField(key, null, Type.HASH);
79+
}
80+
6881
/**
6982
* Creates a geo {@link IndexField} for the given key.
7083
*
@@ -120,6 +133,16 @@ public boolean isText() {
120133
return Type.TEXT.equals(type);
121134
}
122135

136+
/**
137+
* Returns whether the {@link IndexField} is a {@literal hashed}.
138+
*
139+
* @return {@literal true} if {@link IndexField} is hashed.
140+
* @since 2.2
141+
*/
142+
public boolean isHashed() {
143+
return Type.HASH.equals(type);
144+
}
145+
123146
/*
124147
* (non-Javadoc)
125148
* @see java.lang.Object#equals(java.lang.Object)

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/IndexInfo.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,17 @@ public static IndexInfo indexInfoOf(Document sourceDocument) {
9696

9797
} else {
9898

99-
Double keyValue = new Double(value.toString());
99+
if (ObjectUtils.nullSafeEquals("hashed", value)) {
100+
indexFields.add(IndexField.hashed(key));
101+
} else {
100102

101-
if (ONE.equals(keyValue)) {
102-
indexFields.add(IndexField.create(key, ASC));
103-
} else if (MINUS_ONE.equals(keyValue)) {
104-
indexFields.add(IndexField.create(key, DESC));
103+
Double keyValue = new Double(value.toString());
104+
105+
if (ONE.equals(keyValue)) {
106+
indexFields.add(IndexField.create(key, ASC));
107+
} else if (MINUS_ONE.equals(keyValue)) {
108+
indexFields.add(IndexField.create(key, DESC));
109+
}
105110
}
106111
}
107112
}
@@ -206,6 +211,14 @@ public Optional<Duration> getExpireAfter() {
206211
return Optional.ofNullable(expireAfter);
207212
}
208213

214+
/**
215+
* @return {@literal true} if a hashed index field is present.
216+
* @since 2.2
217+
*/
218+
public boolean isHashed() {
219+
return getIndexFields().stream().anyMatch(IndexField::isHashed);
220+
}
221+
209222
@Override
210223
public String toString() {
211224

0 commit comments

Comments
 (0)