org.apache.solr.schema.ChangedSchemaMergeTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.schema.ChangedSchemaMergeTest.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.schema;

import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.FileUtils;

import org.apache.lucene.search.similarities.Similarity;

import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.SimilarityFactory;
import org.apache.solr.search.similarities.LMJelinekMercerSimilarityFactory;
import org.apache.solr.search.similarities.SchemaSimilarityFactory;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.CommitUpdateCommand;
import org.apache.solr.update.UpdateHandler;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChangedSchemaMergeTest extends SolrTestCaseJ4 {

    private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    public static Class<? extends SimilarityFactory> simfac1;
    public static Class<? extends SimilarityFactory> simfac2;

    @BeforeClass
    public static void beforeClass() throws Exception {

        simfac1 = LMJelinekMercerSimilarityFactory.class;
        simfac2 = SchemaSimilarityFactory.class;

        // sanity check our test...
        assertTrue(
                "Effectiveness of tets depends on SchemaSimilarityFactory being SolrCoreAware "
                        + "something changed in the impl and now major portions of this test are useless",
                SolrCoreAware.class.isAssignableFrom(simfac2));

        // randomize the order these similarities are used in the changed schemas
        // to help test proper initialization in both code paths
        if (random().nextBoolean()) {
            Class<? extends SimilarityFactory> tmp = simfac1;
            simfac1 = simfac2;
            simfac2 = tmp;
        }
        System.setProperty("solr.test.simfac1", simfac1.getName());
        System.setProperty("solr.test.simfac2", simfac2.getName());

        initCore();
    }

    private final File solrHomeDirectory = createTempDir().toFile();
    private File schemaFile = null;

    private void addDoc(SolrCore core, String... fieldValues) throws IOException {
        UpdateHandler updater = core.getUpdateHandler();
        AddUpdateCommand cmd = new AddUpdateCommand(new LocalSolrQueryRequest(core, new NamedList<>()));
        cmd.solrDoc = sdoc((Object[]) fieldValues);
        updater.addDoc(cmd);
    }

    private CoreContainer init() throws Exception {
        File changed = new File(solrHomeDirectory, "changed");
        copyMinConf(changed, "name=changed");
        // Overlay with my local schema
        schemaFile = new File(new File(changed, "conf"), "schema.xml");
        FileUtils.writeStringToFile(schemaFile, withWhich, StandardCharsets.UTF_8);

        String discoveryXml = "<solr></solr>";
        File solrXml = new File(solrHomeDirectory, "solr.xml");
        FileUtils.write(solrXml, discoveryXml, StandardCharsets.UTF_8);

        final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath());
        cores.load();
        return cores;
    }

    public void testSanityOfSchemaSimilarityFactoryInform() {
        // sanity check that SchemaSimilarityFactory will throw an Exception if you
        // try to use it w/o inform(SolrCoreAware) otherwise assertSimilarity is useless
        SchemaSimilarityFactory broken = new SchemaSimilarityFactory();
        broken.init(new ModifiableSolrParams());
        // NO INFORM
        try {
            Similarity bogus = broken.getSimilarity();
            fail("SchemaSimilarityFactory should have thrown IllegalStateException b/c inform not used");
        } catch (IllegalStateException expected) {
            assertTrue("GOT: " + expected.getMessage(), expected.getMessage().contains("SolrCoreAware.inform"));
        }
    }

    @Test
    public void testOptimizeDiffSchemas() throws Exception {
        // load up a core (why not put it on disk?)
        CoreContainer cc = init();
        try (SolrCore changed = cc.getCore("changed")) {

            assertSimilarity(changed, simfac1);

            // add some documents
            addDoc(changed, "id", "1", "which", "15", "text", "some stuff with which");
            addDoc(changed, "id", "2", "which", "15", "text", "some stuff with which");
            addDoc(changed, "id", "3", "which", "15", "text", "some stuff with which");
            addDoc(changed, "id", "4", "which", "15", "text", "some stuff with which");
            SolrQueryRequest req = new LocalSolrQueryRequest(changed, new NamedList<>());
            changed.getUpdateHandler().commit(new CommitUpdateCommand(req, false));

            // write the new schema out and make it current
            FileUtils.writeStringToFile(schemaFile, withoutWhich, StandardCharsets.UTF_8);

            IndexSchema iSchema = IndexSchemaFactory.buildIndexSchema("schema.xml", changed.getSolrConfig());
            changed.setLatestSchema(iSchema);

            assertSimilarity(changed, simfac2);
            // sanity check our sanity check
            assertFalse("test is broken: both simfacs are the same", simfac1.equals(simfac2));

            addDoc(changed, "id", "1", "text", "some stuff without which");
            addDoc(changed, "id", "5", "text", "some stuff without which");

            changed.getUpdateHandler().commit(new CommitUpdateCommand(req, false));
            changed.getUpdateHandler().commit(new CommitUpdateCommand(req, true));
        } catch (Throwable e) {
            log.error("Test exception, logging so not swallowed if there is a (finally) shutdown exception: "
                    + e.getMessage(), e);
            throw e;
        } finally {
            if (cc != null)
                cc.shutdown();
        }
    }

    private static void assertSimilarity(SolrCore core, Class<? extends SimilarityFactory> expected) {
        SimilarityFactory actual = core.getLatestSchema().getSimilarityFactory();
        assertNotNull(actual);
        assertEquals(expected, actual.getClass());
        // if SolrCoreAware sim isn't properly initialized, this will throw an exception
        assertNotNull(actual.getSimilarity());
    }

    private static String withWhich = "<schema name=\"tiny\" version=\"1.1\">\n"
            + "    <field name=\"id\" type=\"string\" indexed=\"true\" stored=\"true\" required=\"true\"/>\n"
            + "    <field name=\"text\" type=\"text\" indexed=\"true\" stored=\"true\"/>\n"
            + "    <field name=\"which\" type=\"int\" indexed=\"true\" stored=\"true\"/>\n"
            + "  <uniqueKey>id</uniqueKey>\n" + "\n" + "    <fieldtype name=\"text\" class=\"solr.TextField\">\n"
            + "      <analyzer>\n" + "        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n"
            + "        <filter class=\"solr.LowerCaseFilterFactory\"/>\n" + "      </analyzer>\n" +

            "    </fieldtype>\n" + "    <fieldType name=\"string\" class=\"solr.StrField\"/>\n"
            + "    <fieldType name=\"int\" class=\"solr.TrieIntField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>"
            + "  <similarity class=\"${solr.test.simfac1}\"/> " + "</schema>";

    private static String withoutWhich = "<schema name=\"tiny\" version=\"1.1\">\n"
            + "    <field name=\"id\" type=\"string\" indexed=\"true\" stored=\"true\" required=\"true\"/>\n"
            + "    <field name=\"text\" type=\"text\" indexed=\"true\" stored=\"true\"/>\n"
            + "  <uniqueKey>id</uniqueKey>\n" + "\n" + "    <fieldtype name=\"text\" class=\"solr.TextField\">\n"
            + "      <analyzer>\n" + "        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n"
            + "        <filter class=\"solr.LowerCaseFilterFactory\"/>\n" + "      </analyzer>\n"
            + "    </fieldtype>\n" + "    <fieldType name=\"string\" class=\"solr.StrField\"/>\n"
            + "    <fieldType name=\"int\" class=\"solr.TrieIntField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>"
            + "  <similarity class=\"${solr.test.simfac2}\"/> " + "</schema>";

}