@Override public ResourceIterator<Node> findNodes( final Label myLabel, final String key, final String value, final StringSearchMode searchMode ) { KernelTransaction transaction = statementContext.getKernelTransactionBoundToThisThread( true ); TokenRead tokenRead = transaction.tokenRead(); int labelId = tokenRead.nodeLabel( myLabel.name() ); int propertyId = tokenRead.propertyKey( key ); IndexQuery query; switch ( searchMode ) { case EXACT: query = IndexQuery.exact( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case PREFIX: query = IndexQuery.stringPrefix( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case SUFFIX: query = IndexQuery.stringSuffix( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case CONTAINS: query = IndexQuery.stringContains( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; default: throw new IllegalStateException( "Unknown string search mode: " + searchMode ); } return nodesByLabelAndProperty( transaction, labelId, query ); }
@Test public void testStringContains_FalseForIrrelevant() { StringContainsPredicate p = IndexQuery.stringContains( propId, stringValue( "cat" )); assertFalseForOtherThings( p ); }
@Test public void mustSelectStringForStringContainsPredicate() throws Exception { // given StringContainsPredicate stringContains = IndexQuery.stringContains( PROP_KEY, stringValue( "abc" ) ); // then verifyQueryWithCorrectReader( expectedForStrings(), stringContains ); }
@Test public void testIndexFullSearchWithDuplicates() throws Exception { updateAndCommit( asList( add( 1L, descriptor.schema(), "a" ), add( 2L, descriptor.schema(), "A" ), add( 3L, descriptor.schema(), "apa" ), add( 4L, descriptor.schema(), "apa" ), add( 5L, descriptor.schema(), "apalong" ) ) ); assertThat( query( stringContains( 1, stringValue( "a" ) ) ), equalTo( asList( 1L, 3L, 4L, 5L ) ) ); assertThat( query( stringContains( 1, stringValue( "apa" ) ) ), equalTo( asList( 3L, 4L, 5L ) ) ); assertThat( query( stringContains( 1, stringValue( "apa*" ) ) ), equalTo( Collections.emptyList() ) ); }
@Test void shouldComputeIndexUpdatesForRangeSeekByContainsWhenThereAreNoMatchingNodes() { // GIVEN final ReadableTransactionState state = new TxStateBuilder() .withAdded( 42L, "foo" ) .withAdded( 43L, "bar" ) .build(); // WHEN IndexQuery.StringContainsPredicate indexQuery = IndexQuery.stringContains( index.schema().getPropertyId(), stringValue( "eulav" ) ); AddedAndRemoved changes = indexUpdatesForSuffixOrContains( state, index, indexQuery, IndexOrder.NONE ); AddedWithValuesAndRemoved changesWithValues = indexUpdatesWithValuesForSuffixOrContains( state, index, indexQuery, IndexOrder.NONE ); // THEN assertTrue( changes.getAdded().isEmpty() ); assertFalse( changesWithValues.getAdded().iterator().hasNext() ); }
@Test public void shouldPerformStringContainsSearch() throws Exception { // given Set<Pair<Long,Value>> expected = new HashSet<>(); try ( Transaction tx = beginTransaction() ) { expected.add( nodeWithProp( tx, "gnomebat" ) ); nodeWithPropId( tx, "fishwombat" ); tx.success(); } createIndex(); // when try ( Transaction tx = beginTransaction() ) { int label = tx.tokenRead().nodeLabel( "Node" ); int prop = tx.tokenRead().propertyKey( "prop" ); expected.add( nodeWithProp( tx, "homeopatic" ) ); nodeWithPropId( tx, "telephonecompany" ); IndexReference index = tx.schemaRead().index( label, prop ); assertNodeAndValueForSeek( expected, tx, index, needsValues, "immense", IndexQuery.stringContains( prop, stringValue( "me" ) ) ); } }
@Test public void shouldPerformStringContainmentSearch() throws Exception { // given boolean needsValues = indexProvidesStringValues(); int label = token.nodeLabel( "Node" ); int prop = token.propertyKey( "prop" ); IndexReference index = schemaRead.index( label, prop ); IndexValueCapability stringCapability = index.valueCapability( ValueCategory.TEXT ); try ( NodeValueIndexCursor node = cursors.allocateNodeValueIndexCursor() ) { MutableLongSet uniqueIds = new LongHashSet(); // when read.nodeIndexSeek( index, node, IndexOrder.NONE, needsValues, IndexQuery.stringContains( prop, stringValue( "o" ) ) ); // then assertThat( node.numberOfProperties(), equalTo( 1 ) ); assertFoundNodesAndValue( node, uniqueIds, stringCapability, needsValues, strOne, strTwo1, strTwo2 ); } }
@Test public void testStringContains_SomeValues() { StringContainsPredicate p = IndexQuery.stringContains( propId, stringValue( "cat" )); assertFalse( test( p, "dog" ) ); assertFalse( test( p, "cameraman" ) ); assertFalse( test( p, "Cat" ) ); assertTrue( test( p, "cat" ) ); assertTrue( test( p, "bobcat" ) ); assertTrue( test( p, "scatman" ) ); }
@Test void shouldComputeIndexUpdatesForRangeSeekByContainsWhenThereArePartiallyMatchingNewNodes() { // GIVEN ReadableTransactionState state = new TxStateBuilder() .withAdded( 40L, "Aaron" ) .withAdded( 41L, "Agatha" ) .withAdded( 42L, "Andreas" ) .withAdded( 43L, "Andrea" ) .withAdded( 44L, "Aristotle" ) .withAdded( 45L, "Barbara" ) .withAdded( 46L, "Barbarella" ) .withAdded( 47L, "Cinderella" ) .build(); // WHEN IndexQuery.StringContainsPredicate indexQuery = IndexQuery.stringContains( index.schema().getPropertyId(), stringValue( "arbar" ) ); AddedAndRemoved changes = indexUpdatesForSuffixOrContains( state, index, indexQuery, IndexOrder.NONE ); AddedWithValuesAndRemoved changesWithValues = indexUpdatesWithValuesForSuffixOrContains( state, index, indexQuery, IndexOrder.NONE ); // THEN assertContains( changes.getAdded(), 45L, 46L ); assertContains( changesWithValues.getAdded(), nodeWithPropertyValues( 45L, "Barbara" ), nodeWithPropertyValues( 46L, "Barbarella" ) ); }
private void assertRangeSeekByContainsForOrder( IndexOrder indexOrder ) { // GIVEN ReadableTransactionState state = new TxStateBuilder() .withAdded( 40L, "Smashing" ) .withAdded( 41L, "Bashley" ) .withAdded( 42L, "Crasch" ) .withAdded( 43L, "Mayonnaise" ) .withAdded( 44L, "Seashell" ) .withAdded( 45L, "Ton" ) .withAdded( 46L, "The Flash" ) .withAdded( 47L, "Strayhound" ) .withAdded( 48L, "Trashy" ) .withAdded( 49L, "Andromeda" ) .build(); // WHEN IndexQuery indexQuery = IndexQuery.stringContains( index.schema().getPropertyId(), stringValue( "ash" ) ); AddedAndRemoved changes = indexUpdatesForSuffixOrContains( state, index, indexQuery, indexOrder ); AddedWithValuesAndRemoved changesWithValues = indexUpdatesWithValuesForSuffixOrContains( state, index, indexQuery, indexOrder ); NodeWithPropertyValues[] expected = {nodeWithPropertyValues( 41L, "Bashley" ), nodeWithPropertyValues( 44L, "Seashell" ), nodeWithPropertyValues( 40L, "Smashing" ), nodeWithPropertyValues( 46L, "The Flash" ), nodeWithPropertyValues( 48L, "Trashy" )}; // THEN assertContains( indexOrder, changes, changesWithValues, expected ); } }
@Override public ResourceIterator<Node> findNodes( final Label myLabel, final String key, final String value, final StringSearchMode searchMode ) { KernelTransaction transaction = statementContext.getKernelTransactionBoundToThisThread( true ); TokenRead tokenRead = transaction.tokenRead(); int labelId = tokenRead.nodeLabel( myLabel.name() ); int propertyId = tokenRead.propertyKey( key ); IndexQuery query; switch ( searchMode ) { case EXACT: query = IndexQuery.exact( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case PREFIX: query = IndexQuery.stringPrefix( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case SUFFIX: query = IndexQuery.stringSuffix( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; case CONTAINS: query = IndexQuery.stringContains( propertyId, utf8Value( value.getBytes( UTF_8 ) ) ); break; default: throw new IllegalStateException( "Unknown string search mode: " + searchMode ); } return nodesByLabelAndProperty( transaction, labelId, query ); }