/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.itest.search; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Iterator; import org.junit.Test; import com.enonic.cms.core.content.ContentKey; import com.enonic.cms.core.content.index.ContentIndexQuery; import com.enonic.cms.core.content.resultset.ContentResultSet; import com.enonic.cms.core.search.query.ContentDocument; import com.enonic.cms.core.search.result.FacetResultSet; import com.enonic.cms.core.search.result.FacetsResultSet; import com.enonic.cms.core.search.result.RangeFacetResultEntry; import com.enonic.cms.core.search.result.RangeFacetResultSet; import static org.junit.Assert.*; public class ContentIndexServiceImpl_facetRangeFacetTest extends ContentIndexServiceFacetTestBase { @Test public void dates() { ContentIndexQuery query = new ContentIndexQuery( "" ); final String facetDefinition = "<facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range to=\"2001-01-01\"/>\n" + " <range from=\"2001-01-01\" to=\"2001-01-02\"/>\n" + " <range from=\"2001-01-01T00:00:01\" to=\"2001-01-01 23:59:59\"/>\n" + " <range from=\"2001-01-02T\" />\n" + " <index>data.myDate</index>\n" + " </ranges>\n" + "</facets>\n"; query.setFacets( facetDefinition ); final GregorianCalendar date = new GregorianCalendar( 2008, Calendar.FEBRUARY, 28 ); createContent( 1, "2000-12-31 23:59:59", "data/myDate" ); createContent( 2, "2001-01-01 00:00:00", "data/myDate" ); createContent( 3, "2001-01-01 01:00:00", "data/myDate" ); createContent( 4, "2001-01-01 01:00:01", "data/myDate" ); createContent( 5, "2001-01-01 23:59:58", "data/myDate" ); createContent( 6, "2001-01-02", "data/myDate" ); createContent( 7, "2001-01-03", "data/myDate" ); flushIndex(); final ContentResultSet result = contentIndexService.query( query ); final Iterator<RangeFacetResultEntry> iterator = getResultIterator( result, 4 ); // NOTE: ES-range facets threats 'from' as 'from & including' and 'to' as 'to !including' assertNextEntry( iterator, 1L ); // 2000-12-31 23:59:59 assertNextEntry( iterator, 4L ); // 2001-01-01 00:00:00, 2001-01-01 01:00:00, 2001-01-01 01:00:00:001, 2001-01-01 23:59:58 assertNextEntry( iterator, 3L ); // 2001-01-01 01:00:00, 2001-01-01 01:00:00:001, 2001-01-01 23:59:58 assertNextEntry( iterator, 2L ); // 2001-01-02, 2001-01-03 final String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<content>\n" + " <facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range hits=\"1\" to=\"2001-01-01 00:00:00\" />\n" + " <range hits=\"4\" from=\"2001-01-01 00:00:00\" to=\"2001-01-02 00:00:00\" />\n" + " <range hits=\"3\" from=\"2001-01-01 00:00:01\" to=\"2001-01-01 23:59:59\" />\n" + " <range hits=\"2\" from=\"2001-01-02 00:00:00\" />\n" + " </ranges>\n" + " </facets>\n" + "</content>"; createAndCompareResultAsXml( result, expectedXml ); } @Test public void numeric() { ContentIndexQuery query = new ContentIndexQuery( "" ); final String facetDefinition = "<facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range to=\"1\"/>\n" + " <range from=\"1\" to=\"10\"/>\n" + " <range from=\"10\" to=\"100\"/>\n" + " <range from=\"100\" />\n" + " <index>data.price</index>\n" + " </ranges>\n" + "</facets>\n"; query.setFacets( facetDefinition ); final GregorianCalendar date = new GregorianCalendar( 2008, Calendar.FEBRUARY, 28 ); createContent( 1, "0", "data/price" ); createContent( 2, "0.99", "data/price" ); createContent( 3, "1", "data/price" ); createContent( 4, "1.0", "data/price" ); createContent( 5, "10.0", "data/price" ); createContent( 6, "100", "data/price" ); createContent( 7, "101", "data/price" ); createContent( 8, "1000", "data/price" ); flushIndex(); final ContentResultSet result = contentIndexService.query( query ); final Iterator<RangeFacetResultEntry> iterator = getResultIterator( result, 4 ); // NOTE: ES-range facets threats 'from' as 'from & including' and 'to' as 'to !including' assertNextEntry( iterator, 2L ); // 0, 0.99 assertNextEntry( iterator, 2L ); // 1, 1.0 assertNextEntry( iterator, 1L ); // 10.0 assertNextEntry( iterator, 3L ); // 100, 101, 1000 final String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<content>\n" + " <facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range hits=\"2\" to=\"1.0\" min=\"0.0\" mean=\"0.495\" max=\"0.99\" sum=\"0.99\" />\n" + " <range hits=\"2\" from=\"1.0\" to=\"10.0\" min=\"1.0\" mean=\"1.0\" max=\"1.0\" sum=\"2.0\" />\n" + " <range hits=\"1\" from=\"10.0\" to=\"100.0\" min=\"10.0\" mean=\"10.0\" max=\"10.0\" sum=\"10.0\" />\n" + " <range hits=\"3\" from=\"100.0\" min=\"100.0\" mean=\"400.3333333333333\" max=\"1000.0\" sum=\"1201.0\" />\n" + " </ranges>\n" + " </facets>\n" + "</content>"; createAndCompareResultAsXml( result, expectedXml ); } @Test public void numeric_key_and_valuefields() { ContentIndexQuery query = new ContentIndexQuery( "" ); final String facetDefinition = "<facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range to=\"1\"/>\n" + " <range from=\"1\" to=\"10\"/>\n" + " <range from=\"10\" to=\"100\"/>\n" + " <range from=\"100\" />\n" + " <index>data.price</index>\n" + " <value-index>data.myValue</value-index>\n" + " </ranges>\n" + "</facets>\n"; query.setFacets( facetDefinition ); createAndIndexContent( 1, new String[]{"0", "2"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 2, new String[]{"0.99", "4"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 3, new String[]{"1", "6"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 4, new String[]{"1.0", "8"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 5, new String[]{"10.0", "10"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 6, new String[]{"100", "12"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 7, new String[]{"101", "14"}, new String[]{"data.price", "data.myValue"} ); createAndIndexContent( 8, new String[]{"1000", "16"}, new String[]{"data.price", "data.myValue"} ); flushIndex(); final ContentResultSet result = contentIndexService.query( query ); final Iterator<RangeFacetResultEntry> iterator = getResultIterator( result, 4 ); // NOTE: ES-range facets threats 'from' as 'from & including' and 'to' as 'to !including' assertNextEntry( iterator, 2L ); // 0, 0.99 assertNextEntry( iterator, 2L ); // 1, 1.0 assertNextEntry( iterator, 1L ); // 10.0 assertNextEntry( iterator, 3L ); // 100, 101, 1000 final String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<content>\n" + " <facets>\n" + " <ranges name=\"myRangeFacet\">\n" + " <range hits=\"2\" to=\"1.0\" min=\"2.0\" mean=\"3.0\" max=\"4.0\" sum=\"6.0\" />\n" + " <range hits=\"2\" from=\"1.0\" to=\"10.0\" min=\"6.0\" mean=\"7.0\" max=\"8.0\" sum=\"14.0\" />\n" + " <range hits=\"1\" from=\"10.0\" to=\"100.0\" min=\"10.0\" mean=\"10.0\" max=\"10.0\" sum=\"10.0\" />\n" + " <range hits=\"3\" from=\"100.0\" min=\"12.0\" mean=\"14.0\" max=\"16.0\" sum=\"42.0\" />\n" + " </ranges>\n" + " </facets>\n" + "</content>\n"; createAndCompareResultAsXml( result, expectedXml ); } private Iterator<RangeFacetResultEntry> getResultIterator( final ContentResultSet result, int expectedHits ) { final FacetsResultSet facetsResultSet = result.getFacetsResultSet(); assertTrue( facetsResultSet.iterator().hasNext() ); final FacetResultSet next = facetsResultSet.iterator().next(); assertTrue( next instanceof RangeFacetResultSet ); RangeFacetResultSet rangeFacetResultSet = (RangeFacetResultSet) next; assertEquals( "Wrong number of ranges", expectedHits, rangeFacetResultSet.getResultEntries().size() ); return rangeFacetResultSet.getResultEntries().iterator(); } private void assertNextEntry( final Iterator<RangeFacetResultEntry> iterator, final Long count ) { final RangeFacetResultEntry currentEntry = iterator.next(); assertEquals( count, currentEntry.getCount() ); } private ContentDocument createContent( int contentKey, final String dateString, final String fieldName ) { final GregorianCalendar date = new GregorianCalendar( 2008, Calendar.FEBRUARY, 28 ); ContentDocument doc1 = new ContentDocument( new ContentKey( contentKey ) ); setMetadata( date, doc1 ); doc1.setTitle( "Homer" ); doc1.addUserDefinedField( fieldName, dateString ); contentIndexService.index( doc1 ); return doc1; } }