Single Field Indexes MongoDB Java Example

Indexing MongoDB Java Example

Indexing in MongoDB works in theIndexing in MongoDB same way as it is used to work in relational databases.It helps in the fast retrieval of documents available in MongDB . Having an index over a collection ensures that least numbers of documents are scanned to find the documents matching search criteria. Hence having an understanding of indexes is very important for the efficient performance of your application. In this post we will cover:

  • Basics of indexes
  • Single Field Indexes and How to Apply them ?
  • Performance comparison with and without having an index on collection.

Basics of indexes :
Indexes in MongoDB are stored in BTree where range on the left side of the parent node is always smaller than its parent and on the right side is always bigger than its parent. Performing an inorder traversal over BTree will give you elements in sorted order. Having an index will make sure that your items are stored in the sorted order on the basis of same key which is indexed.btree mongodbBy default each and every collection in the mongodb has an index over its primary key i.e _id. Datatype for _id is ObjectId that we have already seen in the previous post. If no other index is available in the collection , then index over _id will be used for all the queries. We can see all the indexes applied on a collection by using getIndexes() method on collection.

A maximum of 64 indexes can be applied over a collection but in real life you will maximum need 2-3 indexes on a collection.

Single Field Index : In real life you will never rely on default index as it is not because they are not efficient but they might not meet your business needs. In that case you will create an index on one of the keys of the document to meet your business requirements as most of your queries will revolve around that particular key. You can have indexes on combination of keys that are known as Compound Index ,we will talk about them in the next post ,in this post we will focus only on Single Field Index.

How to apply custom index : MongoDB api provides a method ensureIndex() to apply an index over a collection. ensureIndex() has different overloaded version that we can use according to our requirement.

Let’s understand it with help of an example for which document structure looks like this:

{  
  "userName" : "userName1" , 
  "password" : "password1" , 
  "age" : 25 
}

Here , I will insert 1 million records in my collection and then we will search for a particular document before and after index is applied to the collection , we will also compare the performance in both the cases.
Insertion Code :

for(int i=0;i<ONE_MILLION;i++){
      DBObject dbObject = new BasicDBObject();
      dbObject.put("userName", "userName"+i);
      dbObject.put("password", "password"+i);
      dbObject.put("age", Math.random()*100);
      MongoUtils.getCollection(DEFAULT_COLLECTION_NAME).insert(dbObject);
}

Find Without Indexing :

DBObject searchObject = new BasicDBObject();
searchObject.put("userName", "userName87469");
DBObject explainObject = MongoUtils.getCollection("yoMongo").find(searchObject).explain();

Find With Index :

DBObject searchObject = new BasicDBObject();
searchObject.put("userName", "userName87469");
MongoUtils.getCollection("yoMongo").ensureIndex("userName");
DBObject explainObject = MongoUtils.getCollection("yoMongo").find(searchObject).explain();

When I search it without having an index on the collection , it took around 489ms and after index is applied on username key it took only 10 secs. We can also see the internal execution of the query by using explain() method. Below is output that I got after invoking explain in both of the cases.
Without Index :

{ 
 "cursor" : "BasicCursor" , 
 "isMultiKey" : false , 
 "n" : 1 ,
 "nscannedObjects" : 1000000 ,
 "nscanned" : 1000000 ,
 "nscannedObjectsAllPlans" : 1000000 ,
 "nscannedAllPlans" : 1000000 ,
 "scanAndOrder" : false ,
 "indexOnly" : false ,
 "nYields" : 8178 ,
 "nChunkSkips" : 0 ,
 "millis" : 489 ,
  ...
}

With Index :

{ 
 "cursor" : "BtreeCursor userName_1" ,
 "isMultiKey" : false ,
 "n" : 1 ,
 "nscannedObjects" : 1 ,
 "nscanned" : 1 ,
 "nscannedObjectsAllPlans" : 1 ,
 "nscannedAllPlans" : 1 ,
 "scanAndOrder" : false ,
 "indexOnly" : false ,
 "nYields" : 0 ,
 "nChunkSkips" : 0 ,
 "millis" : 10 ,
 "indexBounds" : { "userName" : [ [ "userName87469" ,
 "userName87469"]]} ,
 "allPlans" : [ { "cursor" : "BtreeCursor userName_1" ,
 "isMultiKey" : false ,
 "n" : 1 ,
 "nscannedObjects" : 1 ,
 "nscanned" : 1 ,
 ...
}

Note : I have removed some of the keys from the explain() output as those were not relevant to simple index.

If we compare the cursor key in both the outputs you will see that in the first case no index has been applied while in the 2nd case the field i.e userName on which index is applied is available under cursor.

Other important key is the nscanned that represents how many documents have been scanned by our query to find the matching document , in the 1st case when no index was applied it scanned all the available documents as it doesn’t know how many documents are available in the collection with the same username while in the later case it scanned only 1 document because our documents are already sorted on the key for which we are searching,hence it directly reached to that document and returned the result.

Also notice the millis key that tells us about the time taken by the query in finding the matching documents, as you can see after index is applied query time is reduced by a great extent.

Complete Code :

/**
 * 
 */
package com.techidiocy.mongo.indexing;

import java.util.logging.Logger;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.techidiocy.mongo.MongoUtils;

/**
 * @author yoMongo
 *
 */
public class SimpleIndexComparison {
	
	private static final Logger log = Logger.getAnonymousLogger();
	private static final String DEFAULT_COLLECTION_NAME="yoMongo";

	/**
	 * searching without having an index on collection
	 */
	private static void findWithoutIndex(){
		DBObject searchObject = new BasicDBObject();
		searchObject.put("userName", "userName87469");
		DBObject explainObject = MongoUtils.getCollection(DEFAULT_COLLECTION_NAME).find(searchObject).explain();
		log.info("explainObject without Index--->"+explainObject);
	}
	
	/**
	 * searching with having an index on collection
	 */
	private static void findWithIndex(){
		DBObject searchObject = new BasicDBObject();
		searchObject.put("userName", "userName87469");
		MongoUtils.getCollection(DEFAULT_COLLECTION_NAME).ensureIndex("userName");
		DBObject explainObject = MongoUtils.getCollection(DEFAULT_COLLECTION_NAME).find(searchObject).explain();
		log.info("explainObject with Index--->"+explainObject);
	}

	public static void main(String[] args) {
		MongoUtils.insertMillionRecords();
		SimpleIndexComparison.findWithoutIndex();
		SimpleIndexComparison.findWithIndex();
		MongoUtils.getCollection(DEFAULT_COLLECTION_NAME).drop();
	}

}

All the examples can be downloaded from here.
Disclaimer : All the images belong to their respective owners.

Let'sConnect

Saurabh Jain

A Developer working on Enterprise applications ,Distributed Systems, Hadoop and BigData.This blog is about my experience working mostly on Java technologies ,NoSQL ,git , maven and Hadoop ecosystem.
Let'sConnect

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

One thought on “Single Field Indexes MongoDB Java Example

Add Comment Register



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>