mirror of https://github.com/apache/lucene.git
Revert "SOLR-14067: v3 Create /contrib/scripting module with ScriptingUpdateProcessor (#2215)"
This reverts commit cf5db8d651
.
This commit is contained in:
parent
f942b2dd8a
commit
ce1bba6d66
|
@ -66,7 +66,6 @@ configure(rootProject) {
|
|||
":solr:contrib:langid",
|
||||
":solr:contrib:jaegertracer-configurator",
|
||||
":solr:contrib:prometheus-exporter",
|
||||
":solr:contrib:scripting",
|
||||
":solr:test-framework",
|
||||
]
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ include "solr:contrib:extraction"
|
|||
include "solr:contrib:langid"
|
||||
include "solr:contrib:jaegertracer-configurator"
|
||||
include "solr:contrib:prometheus-exporter"
|
||||
include "solr:contrib:scripting"
|
||||
include "solr:contrib:ltr"
|
||||
include "solr:webapp"
|
||||
include "solr:test-framework"
|
||||
|
|
|
@ -188,9 +188,6 @@ Other Changes
|
|||
|
||||
* SOLR-14297: Replace commons-codec Base64 with JDK8 Base64 (Andras Salamon via Houston Putman)
|
||||
|
||||
* SOLR-14067: StatelessScriptUpdateProcessorFactory moved to it's own /contrib/scripting/ package instead
|
||||
of shipping as part of Solr due to security concerns. Renamed to ScriptUpdateProcessorFactory for simpler name. (Eric Pugh)
|
||||
|
||||
Bug Fixes
|
||||
---------------------
|
||||
* SOLR-14546: Fix for a relatively hard to hit issue in OverseerTaskProcessor that could lead to out of order execution
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
Welcome to Apache Solr Scripting!
|
||||
===============================
|
||||
|
||||
# Introduction
|
||||
|
||||
The Scripting contrib module pulls together various scripting related functions.
|
||||
|
||||
Today, the ScriptUpdateProcessorFactory allows Java scripting engines to support scripts written in languages such as JavaScript, Ruby, Python, and Groovy to be used during Solr document update processing, allowing dramatic flexibility in expressing custom document processing before being indexed. It exposes hooks for commit, delete, etc, but add is the most common usage. It is implemented as an UpdateProcessor to be placed in an UpdateChain.
|
||||
|
||||
## Getting Started
|
||||
|
||||
For information on how to get started please see:
|
||||
* [Solr Reference Guide's section on Update Request Processors](https://lucene.apache.org/solr/guide/update-request-processors.html)
|
||||
* [Solr Reference Guide's section on ScriptUpdateProcessorFactory](https://lucene.apache.org/solr/guide/script-update-processor.html)
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
apply plugin: 'java-library'
|
||||
|
||||
description = 'Scripting Package'
|
||||
|
||||
dependencies {
|
||||
implementation project(':solr:core')
|
||||
testImplementation project(':solr:test-framework')
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for scripting during document updates.
|
||||
*/
|
||||
package org.apache.solr.scripting.update;
|
|
@ -1,26 +0,0 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<html>
|
||||
<body>
|
||||
Apache Solr Search Server: Scripting contrib
|
||||
|
||||
<p>
|
||||
This package provides an Update Processor that allows for Java scripting engines
|
||||
to be used during the Solr document update processing.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- This file is designed to test that loading a .xml file into
|
||||
a script engine that is configured for JavaScript properly raises
|
||||
an exception.
|
||||
|
||||
-->
|
||||
|
||||
<foo version="1.0">
|
||||
<bar/>
|
||||
</foo>
|
|
@ -1,73 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- The Solr schema file. This file should be named "schema.xml" and
|
||||
should be located where the classloader for the Solr webapp can find it.
|
||||
|
||||
This schema is used for testing, and as such has everything and the
|
||||
kitchen sink thrown in. See example/solr/conf/schema.xml for a
|
||||
more concise example.
|
||||
|
||||
-->
|
||||
|
||||
<schema name="test" version="1.6">
|
||||
|
||||
<fieldType name="int" class="${solr.tests.IntegerFieldType}" docValues="${solr.tests.numeric.dv}" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
<fieldType name="double" class="${solr.tests.DoubleFieldType}" docValues="${solr.tests.numeric.dv}" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
|
||||
|
||||
<fieldType name="string" class="solr.StrField" sortMissingLast="true"/>
|
||||
<!-- solr.TextField allows the specification of custom
|
||||
text analyzers specified as a tokenizer and a list
|
||||
of token filters.
|
||||
-->
|
||||
<fieldType name="text" class="solr.TextField">
|
||||
<analyzer>
|
||||
<tokenizer class="solr.StandardTokenizerFactory"/>
|
||||
<filter class="solr.LowerCaseFilterFactory"/>
|
||||
<filter class="solr.StopFilterFactory"/>
|
||||
<filter class="solr.PorterStemFilterFactory"/>
|
||||
</analyzer>
|
||||
</fieldType>
|
||||
|
||||
<fieldType name="nametext" class="solr.TextField">
|
||||
<analyzer class="org.apache.lucene.analysis.core.WhitespaceAnalyzer"/>
|
||||
</fieldType>
|
||||
|
||||
|
||||
<field name="id" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
|
||||
<field name="name" type="nametext" indexed="true" stored="true"/>
|
||||
<field name="subject" type="text" indexed="true" stored="true"/>
|
||||
|
||||
|
||||
<!-- Dynamic field definitions. If a field name is not found, dynamicFields
|
||||
will be used if the name matches any of the patterns.
|
||||
RESTRICTION: the glob-like pattern in the name attribute must have
|
||||
a "*" only at the start or the end.
|
||||
EXAMPLE: name="*_i" will match any field ending in _i (like myid_i, z_i)
|
||||
Longer patterns will be matched first. if equal size patterns
|
||||
both match, the first appearing in the schema will be used.
|
||||
-->
|
||||
<dynamicField name="*_i" type="int" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_d" type="double" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_s" type="string" indexed="true" stored="true"/>
|
||||
<dynamicField name="*_sm" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||
|
||||
<uniqueKey>id</uniqueKey>
|
||||
|
||||
|
||||
</schema>
|
|
@ -1,51 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!--
|
||||
|
||||
A solrconfig.xml snippet containing indexConfig settings for randomized testing.
|
||||
|
||||
-->
|
||||
<indexConfig>
|
||||
<!-- this sys property is not set by SolrTestCaseJ4 because we ideally want to use
|
||||
the RandomMergePolicy in all tests - but some tests expect very specific
|
||||
Merge behavior, so those tests can set it as needed.
|
||||
-->
|
||||
<mergePolicyFactory class="${solr.tests.mergePolicyFactory:org.apache.solr.util.RandomMergePolicyFactory}" />
|
||||
|
||||
<useCompoundFile>${useCompoundFile:false}</useCompoundFile>
|
||||
|
||||
<maxBufferedDocs>${solr.tests.maxBufferedDocs}</maxBufferedDocs>
|
||||
<ramBufferSizeMB>${solr.tests.ramBufferSizeMB}</ramBufferSizeMB>
|
||||
<maxCommitMergeWaitTime>${solr.tests.maxCommitMergeWaitTime:-1}</maxCommitMergeWaitTime>
|
||||
<ramPerThreadHardLimitMB>${solr.tests.ramPerThreadHardLimitMB}</ramPerThreadHardLimitMB>
|
||||
|
||||
<mergeScheduler class="${solr.tests.mergeScheduler}" />
|
||||
|
||||
<writeLockTimeout>1000</writeLockTimeout>
|
||||
<commitLockTimeout>10000</commitLockTimeout>
|
||||
|
||||
<!-- this sys property is not set by SolrTestCaseJ4 because almost all tests should
|
||||
use the single process lockType for speed - but tests that explicitly need
|
||||
to vary the lockType canset it as needed.
|
||||
-->
|
||||
<lockType>${solr.tests.lockType:single}</lockType>
|
||||
|
||||
<infoStream>${solr.tests.infostream:false}</infoStream>
|
||||
|
||||
</indexConfig>
|
|
@ -1,126 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Test Config for ScriptUpdateProcessorFactory
|
||||
|
||||
-->
|
||||
<config>
|
||||
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
|
||||
<xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<requestHandler name="/select" class="solr.SearchHandler"></requestHandler>
|
||||
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
|
||||
<schemaFactory class="ClassicIndexSchemaFactory"/>
|
||||
|
||||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="engine">javascript</str>
|
||||
<str name="script">missleading.extension.updateprocessor.js.txt</str>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="run-no-scripts">
|
||||
<!-- for bypassing all scripts -->
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="single-script">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">trivial.updateprocessor0.js</str>
|
||||
<lst name="params">
|
||||
<bool name="boolValue">true</bool>
|
||||
<int name="intValue">1</int>
|
||||
</lst>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="dual-scripts-arr">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<arr name="script">
|
||||
<str>trivial.updateprocessor0.js</str>
|
||||
<str>trivial.updateprocessor1.js</str>
|
||||
</arr>
|
||||
<lst name="params">
|
||||
<bool name="boolValue">true</bool>
|
||||
<int name="intValue">1</int>
|
||||
</lst>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="dual-scripts-strs">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">trivial.updateprocessor0.js</str>
|
||||
<str name="script">trivial.updateprocessor1.js</str>
|
||||
<lst name="params">
|
||||
<bool name="boolValue">true</bool>
|
||||
<int name="intValue">1</int>
|
||||
</lst>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="conditional-scripts">
|
||||
<!-- multiple scripts,
|
||||
test that the first one can conditionally stop execution -->
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">conditional.updateprocessor.js</str>
|
||||
<str name="script">addfields.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="conditional-script">
|
||||
<!-- single script, followed by another processor
|
||||
(that happens to be a script).
|
||||
test that the first one can conditionally stop execution -->
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">conditional.updateprocessor.js</str>
|
||||
</processor>
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">addfields.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="error-on-add">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">throw.error.on.add.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="missing-functions">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">missing.functions.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="javascript-compatibility">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">cross-compatible.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="evil">
|
||||
<processor class="org.apache.solr.update.processor.scripting.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">evil.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
</config>
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* 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.scripting.update;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import org.apache.solr.core.AbstractBadConfigTestBase;
|
||||
import org.junit.Assume;
|
||||
|
||||
public class TestBadScriptingUpdateProcessorConfig extends AbstractBadConfigTestBase {
|
||||
|
||||
|
||||
public void testBogusScriptEngine() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeTrue(null == (new ScriptEngineManager()).getEngineByName("giberish"));
|
||||
|
||||
assertConfigs("bad-solrconfig-bogus-scriptengine-name.xml",
|
||||
"schema.xml","giberish");
|
||||
}
|
||||
|
||||
public void testMissingScriptFile() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
|
||||
assertConfigs("bad-solrconfig-missing-scriptfile.xml",
|
||||
"schema.xml","a-file-name-that-does-not-exist.js");
|
||||
}
|
||||
|
||||
public void testInvalidScriptFile() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByName("javascript"));
|
||||
assertConfigs("bad-solrconfig-invalid-scriptfile.xml",
|
||||
"schema.xml","invalid.script.xml");
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.scripting.update;
|
||||
package org.apache.solr.update.processor;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.scripting.update;
|
||||
package org.apache.solr.update.processor;
|
||||
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.SolrException.ErrorCode;
|
||||
|
@ -26,8 +26,6 @@ import org.apache.solr.request.SolrQueryRequest;
|
|||
import org.apache.solr.request.LocalSolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.update.*;
|
||||
import org.apache.solr.update.processor.UpdateRequestProcessor;
|
||||
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
|
||||
import org.apache.solr.util.plugin.SolrCoreAware;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
@ -60,33 +58,34 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* An update request processor factory that enables the use of update
|
||||
* processors implemented as scripts which can be loaded from the
|
||||
* configSet. Previously known as the StatelessScriptUpdateProcessorFactory.
|
||||
* An update request processor factory that enables the use of update
|
||||
* processors implemented as scripts which can be loaded by the
|
||||
* {@link SolrResourceLoader} (usually via the <code>conf</code> dir for
|
||||
* the SolrCore).
|
||||
* </p>
|
||||
* <p>
|
||||
* This factory requires at least one configuration parameter named
|
||||
* <code>script</code> which may be the name of a script file as a string,
|
||||
* or an array of multiple script files. If multiple script files are
|
||||
* specified, they are executed sequentially in the order specified in the
|
||||
* <code>script</code> which may be the name of a script file as a string,
|
||||
* or an array of multiple script files. If multiple script files are
|
||||
* specified, they are executed sequentially in the order specified in the
|
||||
* configuration -- as if multiple factories were configured sequentially
|
||||
* </p>
|
||||
* <p>
|
||||
* Each script file is expected to declare functions with the same name
|
||||
* as each method in {@link UpdateRequestProcessor}, using the same
|
||||
* arguments. One slight deviation is in the optional return value from
|
||||
* these functions: If a script function has a <code>boolean</code> return
|
||||
* value, and that value is <code>false</code> then the processor will
|
||||
* cleanly terminate processing of the command and return, without forwarding
|
||||
* Each script file is expected to declare functions with the same name
|
||||
* as each method in {@link UpdateRequestProcessor}, using the same
|
||||
* arguments. One slight deviation is in the optional return value from
|
||||
* these functions: If a script function has a <code>boolean</code> return
|
||||
* value, and that value is <code>false</code> then the processor will
|
||||
* cleanly terminate processing of the command and return, without forwarding
|
||||
* the command on to the next script or processor in the chain.
|
||||
* Due to limitations in the {@link ScriptEngine} API used by
|
||||
* Due to limitations in the {@link ScriptEngine} API used by
|
||||
* this factory, it can not enforce that all functions exist on initialization,
|
||||
* so errors from missing functions will only be generated at runtime when
|
||||
* the chain attempts to use them.
|
||||
* </p>
|
||||
* <p>
|
||||
* The factory may also be configured with an optional "params" argument,
|
||||
* which can be an {@link NamedList} (or array, or any other simple Java
|
||||
* The factory may also be configured with an optional "params" argument,
|
||||
* which can be an {@link NamedList} (or array, or any other simple Java
|
||||
* object) which will be put into the global scope for each script.
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -98,40 +97,40 @@ import org.slf4j.LoggerFactory;
|
|||
* <li>params - The "params" init argument in the factory configuration (if any)</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Internally this update processor uses JDK 6 scripting engine support,
|
||||
* and any {@link Invocable} implementations of <code>ScriptEngine</code>
|
||||
* that can be loaded using the Solr Plugin ClassLoader may be used.
|
||||
* By default, the engine used for each script is determined by the file
|
||||
* extension (ie: a *.js file will be treated as a JavaScript script) but
|
||||
* this can be overridden by specifying an explicit "engine" name init
|
||||
* param for the factory, which identifies a registered name of a
|
||||
* {@link ScriptEngineFactory}.
|
||||
* (This may be particularly useful if multiple engines are available for
|
||||
* the same scripting language, and you wish to force the usage of a
|
||||
* Internally this update processor uses JDK 6 scripting engine support,
|
||||
* and any {@link Invocable} implementations of <code>ScriptEngine</code>
|
||||
* that can be loaded using the Solr Plugin ClassLoader may be used.
|
||||
* By default, the engine used for each script is determined by the filed
|
||||
* extension (ie: a *.js file will be treated as a JavaScript script) but
|
||||
* this can be overridden by specifying an explicit "engine" name init
|
||||
* param for the factory, which identifies a registered name of a
|
||||
* {@link ScriptEngineFactory}.
|
||||
* (This may be particularly useful if multiple engines are available for
|
||||
* the same scripting language, and you wish to force the usage of a
|
||||
* particular engine because of known quirks)
|
||||
* </p>
|
||||
* <p>
|
||||
* A new {@link ScriptEngineManager} is created for each
|
||||
* <code>SolrQueryRequest</code> defining a "global" scope for the script(s)
|
||||
* which is request specific. Separate <code>ScriptEngine</code> instances
|
||||
* are then used to evaluate the script files, resulting in an "engine" scope
|
||||
* A new {@link ScriptEngineManager} is created for each
|
||||
* <code>SolrQueryRequest</code> defining a "global" scope for the script(s)
|
||||
* which is request specific. Separate <code>ScriptEngine</code> instances
|
||||
* are then used to evaluate the script files, resulting in an "engine" scope
|
||||
* that is specific to each script.
|
||||
* </p>
|
||||
* <p>
|
||||
* A simple example...
|
||||
* </p>
|
||||
* <pre class="prettyprint">
|
||||
* <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
* <processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
* <str name="script">updateProcessor.js</str>
|
||||
* </processor>
|
||||
* </pre>
|
||||
* <p>
|
||||
* A more complex example involving multiple scripts in different languages,
|
||||
* and a "params" <code>NamedList</code> that will be put into the global
|
||||
* A more complex example involving multiple scripts in different languages,
|
||||
* and a "params" <code>NamedList</code> that will be put into the global
|
||||
* scope of each script...
|
||||
* </p>
|
||||
* <pre class="prettyprint">
|
||||
* <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
* <processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
* <arr name="script">
|
||||
* <str name="script">first-processor.js</str>
|
||||
* <str name="script">second-processor.py</str>
|
||||
|
@ -143,11 +142,11 @@ import org.slf4j.LoggerFactory;
|
|||
* </processor>
|
||||
* </pre>
|
||||
* <p>
|
||||
* An example where the script file extensions are ignored, and an
|
||||
* An example where the script file extensions are ignored, and an
|
||||
* explicit script engine is used....
|
||||
* </p>
|
||||
* <pre class="prettyprint">
|
||||
* <processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
* <processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
* <arr name="script">
|
||||
* <str name="script">first-processor.txt</str>
|
||||
* <str name="script">second-processor.txt</str>
|
||||
|
@ -155,10 +154,10 @@ import org.slf4j.LoggerFactory;
|
|||
* <str name="engine">rhino</str>
|
||||
* </processor>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
|
||||
public class StatelessScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory implements SolrCoreAware {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
|
@ -183,8 +182,8 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
Collection<String> scripts =
|
||||
args.removeConfigArgs(SCRIPT_ARG);
|
||||
if (scripts.isEmpty()) {
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"ScriptUpdateProcessorFactory must be " +
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"StatelessScriptUpdateProcessorFactory must be " +
|
||||
"initialized with at least one " + SCRIPT_ARG);
|
||||
}
|
||||
scriptFiles = new ArrayList<>();
|
||||
|
@ -200,8 +199,8 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
engineName = (String)engine;
|
||||
} else {
|
||||
throw new SolrException
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
|
||||
(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"'" + ENGINE_NAME_ARG + "' init param must be a String (found: " +
|
||||
engine.getClass() + ")");
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +246,7 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
req.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,13 +259,13 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
* @param rsp The solr response
|
||||
* @return The list of initialized script engines.
|
||||
*/
|
||||
private List<EngineInfo> initEngines(SolrQueryRequest req,
|
||||
SolrQueryResponse rsp)
|
||||
private List<EngineInfo> initEngines(SolrQueryRequest req,
|
||||
SolrQueryResponse rsp)
|
||||
throws SolrException {
|
||||
|
||||
|
||||
List<EngineInfo> scriptEngines = new ArrayList<>();
|
||||
|
||||
ScriptEngineManager scriptEngineManager
|
||||
ScriptEngineManager scriptEngineManager
|
||||
= new ScriptEngineManager(resourceLoader.getClassLoader());
|
||||
|
||||
scriptEngineManager.put("logger", log);
|
||||
|
@ -282,10 +281,10 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
engine = scriptEngineManager.getEngineByName(engineName);
|
||||
if (engine == null) {
|
||||
String details = getSupportedEngines(scriptEngineManager, false);
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"No ScriptEngine found by name: "
|
||||
+ engineName +
|
||||
(null != details ?
|
||||
+ engineName +
|
||||
(null != details ?
|
||||
" -- supported names: " + details : ""));
|
||||
}
|
||||
} else {
|
||||
|
@ -293,18 +292,18 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
(scriptFile.getExtension());
|
||||
if (engine == null) {
|
||||
String details = getSupportedEngines(scriptEngineManager, true);
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"No ScriptEngine found by file extension: "
|
||||
+ scriptFile.getFileName() +
|
||||
(null != details ?
|
||||
+ scriptFile.getFileName() +
|
||||
(null != details ?
|
||||
" -- supported extensions: " + details : ""));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (! (engine instanceof Invocable)) {
|
||||
String msg =
|
||||
"Engine " + ((null != engineName) ? engineName :
|
||||
String msg =
|
||||
"Engine " + ((null != engineName) ? engineName :
|
||||
("for script " + scriptFile.getFileName())) +
|
||||
" does not support function invocation (via Invocable): " +
|
||||
engine.getClass().toString() + " (" +
|
||||
|
@ -320,7 +319,7 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
scriptEngines.add(new EngineInfo((Invocable)engine, scriptFile));
|
||||
try {
|
||||
Reader scriptSrc = scriptFile.openReader(resourceLoader);
|
||||
|
||||
|
||||
try {
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
|
@ -334,23 +333,23 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
throw (ScriptException) e.getException();
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to evaluate script: " +
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to evaluate script: " +
|
||||
scriptFile.getFileName(), e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(scriptSrc);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to evaluate script: " +
|
||||
scriptFile.getFileName(), ioe);
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to evaluate script: " +
|
||||
scriptFile.getFileName(), ioe);
|
||||
}
|
||||
}
|
||||
return scriptEngines;
|
||||
}
|
||||
|
||||
/**
|
||||
* For error messages - returns null if there are any exceptions of any
|
||||
* For error messages - returns null if there are any exceptions of any
|
||||
* kind building the string (or of the list is empty for some unknown reason).
|
||||
* @param ext - if true, list of extensions, otherwise a list of engine names
|
||||
*/
|
||||
|
@ -404,7 +403,7 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
if (invokeFunction("processDelete", cmd)) {
|
||||
super.processDelete(cmd);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -436,9 +435,9 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* returns true if processing should continue, or false if the
|
||||
* request should be ended now. Result value is computed from the return
|
||||
* value of the script function if: it exists, is non-null, and can be
|
||||
* returns true if processing should continue, or false if the
|
||||
* request should be ended now. Result value is computed from the return
|
||||
* value of the script function if: it exists, is non-null, and can be
|
||||
* cast to a java Boolean.
|
||||
*/
|
||||
private boolean invokeFunction(String name, Object... cmd) {
|
||||
|
@ -462,10 +461,10 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
|
|||
}
|
||||
|
||||
} catch (ScriptException | NoSuchMethodException e) {
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to invoke function " + name +
|
||||
" in script: " +
|
||||
engine.getScriptFile().getFileName() +
|
||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Unable to invoke function " + name +
|
||||
" in script: " +
|
||||
engine.getScriptFile().getFileName() +
|
||||
": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
|
||||
|
||||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="engine">giberish</str>
|
||||
<str name="script">missleading.extension.updateprocessor.js.txt</str>
|
||||
</processor>
|
|
@ -22,10 +22,10 @@
|
|||
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
|
||||
|
||||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="engine">javascript</str>
|
||||
<!-- not parsable as javascript -->
|
||||
<str name="script">invalid.script.xml</str>
|
||||
<str name="script">currency.xml</str>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
|
@ -22,7 +22,7 @@
|
|||
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
|
||||
|
||||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">a-file-name-that-does-not-exist.js</str>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
|
@ -18,7 +18,7 @@
|
|||
-->
|
||||
|
||||
<!--
|
||||
Test Config for ScriptUpdateProcessorFactory
|
||||
Test Config that for ScriptUpdateProcessor
|
||||
|
||||
-->
|
||||
<config>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<schemaFactory class="ClassicIndexSchemaFactory"/>
|
||||
|
||||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="engine">javascript</str>
|
||||
<str name="script">missleading.extension.updateprocessor.js.txt</str>
|
||||
</processor>
|
||||
|
@ -42,7 +42,7 @@
|
|||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="single-script">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">trivial.updateprocessor0.js</str>
|
||||
<lst name="params">
|
||||
<bool name="boolValue">true</bool>
|
||||
|
@ -53,7 +53,7 @@
|
|||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="dual-scripts-arr">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<arr name="script">
|
||||
<str>trivial.updateprocessor0.js</str>
|
||||
<str>trivial.updateprocessor1.js</str>
|
||||
|
@ -67,7 +67,7 @@
|
|||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="dual-scripts-strs">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">trivial.updateprocessor0.js</str>
|
||||
<str name="script">trivial.updateprocessor1.js</str>
|
||||
<lst name="params">
|
||||
|
@ -79,46 +79,46 @@
|
|||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="conditional-scripts">
|
||||
<!-- multiple scripts,
|
||||
<!-- multiple scripts,
|
||||
test that the first one can conditionally stop execution -->
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">conditional.updateprocessor.js</str>
|
||||
<str name="script">addfields.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="conditional-script">
|
||||
<!-- single script, followed by another processor
|
||||
(that happens to be a script).
|
||||
<!-- single script, followed by another processor
|
||||
(that happens to be a script).
|
||||
test that the first one can conditionally stop execution -->
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">conditional.updateprocessor.js</str>
|
||||
</processor>
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">addfields.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="error-on-add">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">throw.error.on.add.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="missing-functions">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">missing.functions.updateprocessor.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="javascript-compatibility">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">cross-compatible.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<updateRequestProcessorChain name="evil">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">evil.js</str>
|
||||
</processor>
|
||||
</updateRequestProcessorChain>
|
|
@ -0,0 +1,23 @@
|
|||
function processAdd(cmd) {
|
||||
// Integer.valueOf is needed here to get a tru java object, because
|
||||
// all javascript numbers are floating point (ie: java.lang.Double)
|
||||
cmd.getSolrInputDocument().addField("script_added_i",
|
||||
java.lang.Integer.valueOf(42));
|
||||
cmd.getSolrInputDocument().addField("script_added_d", 42.3);
|
||||
|
||||
}
|
||||
function processDelete() {
|
||||
// NOOP
|
||||
}
|
||||
function processCommit() {
|
||||
// NOOP
|
||||
}
|
||||
function processRollback() {
|
||||
// NOOP
|
||||
}
|
||||
function processMergeIndexes() {
|
||||
// NOOP
|
||||
}
|
||||
function finish() {
|
||||
// NOOP
|
||||
}
|
|
@ -37,9 +37,12 @@
|
|||
|
||||
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
|
||||
|
||||
<lib dir="${solr.install.dir:../../../../../}/contrib/scripting/build/libs/" regex="solr-scripting-\d.*\.jar" />
|
||||
|
||||
<updateHandler class="solr.DirectUpdateHandler2">
|
||||
<commitWithin>
|
||||
<softCommit>${solr.commitwithin.softcommit:true}</softCommit>
|
||||
</commitWithin>
|
||||
|
||||
</updateHandler>
|
||||
<requestHandler name="/select" class="solr.SearchHandler">
|
||||
<lst name="defaults">
|
||||
<str name="echoParams">explicit</str>
|
||||
|
@ -52,10 +55,11 @@
|
|||
<updateRequestProcessorChain name="force-script-engine" default="true">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="engine">javascript</str>
|
||||
<str name="script">trivial.updateprocessor.js</str>
|
||||
<str name="script">missleading.extension.updateprocessor.js.txt</str>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<requestHandler name="/update" class="solr.UpdateRequestHandler" />
|
||||
</config>
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
function processAdd(cmd) {
|
||||
// Integer.valueOf is needed here to get a tru java object, because
|
||||
// all javascript numbers are floating point (ie: java.lang.Double)
|
||||
cmd.getSolrInputDocument().addField("script_added_i",
|
||||
java.lang.Integer.valueOf(42));
|
||||
}
|
||||
|
||||
function processDelete() {
|
||||
// NOOP
|
||||
}
|
||||
function processCommit() {
|
||||
// NOOP
|
||||
}
|
||||
function processRollback() {
|
||||
// NOOP
|
||||
}
|
||||
function processMergeIndexes() {
|
||||
// NOOP
|
||||
}
|
||||
function finish() {
|
||||
// NOOP
|
||||
}
|
|
@ -16,6 +16,10 @@
|
|||
*/
|
||||
package org.apache.solr.core;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import org.junit.Assume;
|
||||
|
||||
public class TestBadConfig extends AbstractBadConfigTestBase {
|
||||
|
||||
public void testUnsetSysProperty() throws Exception {
|
||||
|
@ -40,7 +44,7 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
|
|||
}
|
||||
|
||||
public void testUpdateLogButNoVersionField() throws Exception {
|
||||
|
||||
|
||||
System.setProperty("enable.update.log", "true");
|
||||
try {
|
||||
assertConfigs("solrconfig.xml", "schema12.xml", "_version_");
|
||||
|
@ -49,6 +53,28 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testBogusScriptEngine() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeTrue(null == (new ScriptEngineManager()).getEngineByName("giberish"));
|
||||
|
||||
assertConfigs("bad-solrconfig-bogus-scriptengine-name.xml",
|
||||
"schema.xml","giberish");
|
||||
}
|
||||
|
||||
public void testMissingScriptFile() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
|
||||
assertConfigs("bad-solrconfig-missing-scriptfile.xml",
|
||||
"schema.xml","a-file-name-that-does-not-exist.js");
|
||||
}
|
||||
|
||||
public void testInvalidScriptFile() throws Exception {
|
||||
// sanity check
|
||||
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByName("javascript"));
|
||||
assertConfigs("bad-solrconfig-invalid-scriptfile.xml",
|
||||
"schema.xml","currency.xml");
|
||||
}
|
||||
|
||||
public void testBogusMergePolicy() throws Exception {
|
||||
assertConfigs("bad-mpf-solrconfig.xml", "schema-minimal.xml",
|
||||
"DummyMergePolicyFactory");
|
||||
|
@ -63,7 +89,7 @@ public class TestBadConfig extends AbstractBadConfigTestBase {
|
|||
assertConfigs("bad-solrconfig-managed-schema-named-schema.xml.xml",
|
||||
"schema-minimal.xml", "managedSchemaResourceName can't be 'schema.xml'");
|
||||
}
|
||||
|
||||
|
||||
public void testUnknownSchemaAttribute() throws Exception {
|
||||
assertConfigs("bad-solrconfig-unexpected-schema-attribute.xml", "schema-minimal.xml",
|
||||
"Unexpected arg(s): {bogusParam=bogusValue}");
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.scripting.update;
|
||||
package org.apache.solr.update.processor;
|
||||
|
||||
import org.apache.lucene.util.Constants;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.solr.scripting.update;
|
||||
package org.apache.solr.update.processor;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
@ -25,26 +25,24 @@ import org.apache.solr.common.SolrException;
|
|||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
import org.apache.solr.core.SolrCore;
|
||||
import org.apache.solr.update.processor.UpdateProcessorTestBase;
|
||||
import org.apache.solr.update.processor.UpdateRequestProcessorChain;
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
/**
|
||||
* Tests {@link ScriptUpdateProcessorFactory}.
|
||||
* Tests {@link StatelessScriptUpdateProcessorFactory}.
|
||||
*
|
||||
* TODO: This test, to run from an IDE, requires a working directory of <path-to>/solr/contrib/scripting/src/test-files. Fix!
|
||||
* TODO: This test, to run from an IDE, requires a working directory of <path-to>/solr/core/src/test-files. Fix!
|
||||
*/
|
||||
public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
||||
public class StatelessScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
Assume.assumeNotNull((new ScriptEngineManager()).getEngineByExtension("js"));
|
||||
initCore("solrconfig-script-updateprocessor.xml", "schema.xml");
|
||||
initCore("solrconfig-script-updateprocessor.xml", "schema12.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* simple test of a basic script processor chain using the full
|
||||
* simple test of a basic script processor chain using the full
|
||||
* RequestHandler + UpdateProcessorChain flow
|
||||
*/
|
||||
public void testFullRequestHandlerFlow() throws Exception {
|
||||
|
@ -64,13 +62,13 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
// clean up
|
||||
processDeleteById("run-no-scripts","4055");
|
||||
processCommit("run-no-scripts");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testSingleScript() throws Exception {
|
||||
SolrCore core = h.getCore();
|
||||
UpdateRequestProcessorChain chained = core.getUpdateProcessingChain("single-script");
|
||||
final ScriptUpdateProcessorFactory factory = ((ScriptUpdateProcessorFactory) chained.getProcessors().get(0));
|
||||
final StatelessScriptUpdateProcessorFactory factory = ((StatelessScriptUpdateProcessorFactory) chained.getProcessors().get(0));
|
||||
final List<String> functionMessages = new ArrayList<>();
|
||||
factory.setScriptEngineCustomizer(new ScriptEngineCustomizer() {
|
||||
@Override
|
||||
|
@ -93,7 +91,7 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
|
||||
processDeleteById("single-script","1");
|
||||
processCommit("single-script");
|
||||
|
||||
|
||||
assertQ("found deleted doc",
|
||||
req("q","id:1")
|
||||
, "//result[@numFound=0]");
|
||||
|
@ -110,12 +108,12 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
public void testMultipleScripts() throws Exception {
|
||||
SolrCore core = h.getCore();
|
||||
|
||||
for (final String chain : new String[] {"dual-scripts-arr",
|
||||
for (final String chain : new String[] {"dual-scripts-arr",
|
||||
"dual-scripts-strs"}) {
|
||||
|
||||
|
||||
UpdateRequestProcessorChain chained = core.getUpdateProcessingChain(chain);
|
||||
final ScriptUpdateProcessorFactory factory =
|
||||
((ScriptUpdateProcessorFactory) chained.getProcessors().get(0));
|
||||
final StatelessScriptUpdateProcessorFactory factory =
|
||||
((StatelessScriptUpdateProcessorFactory) chained.getProcessors().get(0));
|
||||
final List<String> functionMessages = new ArrayList<>();
|
||||
ScriptEngineCustomizer customizer = new ScriptEngineCustomizer() {
|
||||
@Override
|
||||
|
@ -130,12 +128,12 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
doc(f("id", "2"),
|
||||
f("name", " foo "),
|
||||
f("subject", "bar")));
|
||||
|
||||
assertEquals(chain + " didn't add Double field",
|
||||
|
||||
assertEquals(chain + " didn't add Double field",
|
||||
42.3d, d.getFieldValue("script_added_d"));
|
||||
assertEquals(chain + " didn't add integer field",
|
||||
42, d.getFieldValue("script_added_i"));
|
||||
|
||||
|
||||
processCommit("run-no-scripts");
|
||||
|
||||
assertQ(chain + ": couldn't find doc by id",
|
||||
|
@ -144,72 +142,72 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
|
||||
processDeleteById(chain, "2");
|
||||
processCommit(chain);
|
||||
|
||||
|
||||
assertEquals(chain, 6, functionMessages.size());
|
||||
assertTrue(chain, functionMessages.contains("processAdd0"));
|
||||
assertTrue(chain, functionMessages.contains("processAdd1"));
|
||||
assertTrue(chain + ": script order doesn't match conf order",
|
||||
functionMessages.indexOf("processAdd0")
|
||||
functionMessages.indexOf("processAdd0")
|
||||
< functionMessages.indexOf("processAdd1"));
|
||||
|
||||
assertTrue(chain, functionMessages.contains("processDelete0"));
|
||||
assertTrue(chain, functionMessages.contains("processDelete1"));
|
||||
assertTrue(chain + ": script order doesn't match conf order",
|
||||
functionMessages.indexOf("processDelete0")
|
||||
functionMessages.indexOf("processDelete0")
|
||||
< functionMessages.indexOf("processDelete1"));
|
||||
|
||||
assertTrue(chain, functionMessages.contains("processCommit0"));
|
||||
assertTrue(chain, functionMessages.contains("processCommit1"));
|
||||
assertTrue(chain + ": script order doesn't match conf order",
|
||||
functionMessages.indexOf("processCommit0")
|
||||
functionMessages.indexOf("processCommit0")
|
||||
< functionMessages.indexOf("processCommit1"));
|
||||
|
||||
finish(chain);
|
||||
|
||||
|
||||
assertEquals(chain, 8, functionMessages.size());
|
||||
|
||||
assertTrue(chain, functionMessages.contains("finish0"));
|
||||
assertTrue(chain, functionMessages.contains("finish1"));
|
||||
assertTrue(chain + ": script order doesn't match conf order",
|
||||
functionMessages.indexOf("finish0")
|
||||
functionMessages.indexOf("finish0")
|
||||
< functionMessages.indexOf("finish1"));
|
||||
|
||||
assertQ(chain + ": found deleted doc",
|
||||
req("q","id:2")
|
||||
, "//result[@numFound=0]");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testConditionalExecution() throws Exception {
|
||||
for (String chain : new String[] {"conditional-script",
|
||||
for (String chain : new String[] {"conditional-script",
|
||||
"conditional-scripts"}) {
|
||||
|
||||
ModifiableSolrParams reqParams = new ModifiableSolrParams();
|
||||
|
||||
|
||||
SolrInputDocument d = processAdd(chain,
|
||||
reqParams,
|
||||
doc(f("id", "3"),
|
||||
f("name", " foo "),
|
||||
f("subject", "bar")));
|
||||
|
||||
assertFalse(chain + " added String field despite condition",
|
||||
|
||||
assertFalse(chain + " added String field despite condition",
|
||||
d.containsKey("script_added_s"));
|
||||
assertFalse(chain + " added Double field despite condition",
|
||||
assertFalse(chain + " added Double field despite condition",
|
||||
d.containsKey("script_added_d"));
|
||||
|
||||
|
||||
reqParams.add("go-for-it", "true");
|
||||
|
||||
|
||||
d = processAdd(chain,
|
||||
reqParams,
|
||||
doc(f("id", "4"),
|
||||
f("name", " foo "),
|
||||
f("subject", "bar")));
|
||||
|
||||
assertEquals(chain + " didn't add String field",
|
||||
|
||||
assertEquals(chain + " didn't add String field",
|
||||
"i went for it", d.getFieldValue("script_added_s"));
|
||||
assertEquals(chain +" didn't add Double field",
|
||||
assertEquals(chain +" didn't add Double field",
|
||||
42.3d, d.getFieldValue("script_added_d"));
|
||||
assertEquals(chain + " didn't add integer field",
|
||||
42, d.getFieldValue("script_added_i"));
|
||||
|
@ -224,8 +222,8 @@ public class ScriptUpdateProcessorFactoryTest extends UpdateProcessorTestBase {
|
|||
doc(f("id", "5"),
|
||||
f("name", " foo "),
|
||||
f("subject", "bar")));
|
||||
|
||||
assertEquals(chain +" didn't add Double field",
|
||||
|
||||
assertEquals(chain +" didn't add Double field",
|
||||
42.3d, d.getFieldValue("script_added_d"));
|
||||
assertEquals(chain + " didn't add integer field",
|
||||
42, d.getFieldValue("script_added_i"));
|
|
@ -52,7 +52,6 @@ dependencies {
|
|||
":solr:contrib:langid",
|
||||
":solr:contrib:ltr",
|
||||
":solr:contrib:prometheus-exporter",
|
||||
":solr:contrib:scripting"
|
||||
].each { contribName ->
|
||||
distSolr project(contribName)
|
||||
contrib project(path: contribName, configuration: "packaging")
|
||||
|
|
|
@ -83,8 +83,6 @@
|
|||
|
||||
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-ltr-\d.*\.jar" />
|
||||
|
||||
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-scripting-\d.*\.jar" />
|
||||
|
||||
<!-- an exact 'path' can be used instead of a 'dir' to specify a
|
||||
specific jar file. This will cause a serious error to be logged
|
||||
if it can't be loaded.
|
||||
|
@ -381,11 +379,11 @@
|
|||
<query>
|
||||
|
||||
<!-- Maximum number of clauses allowed when parsing a boolean query string.
|
||||
|
||||
|
||||
This limit only impacts boolean queries specified by a user as part of a query string,
|
||||
and provides per-collection controls on how complex user specified boolean queries can
|
||||
be. Query strings that specify more clauses then this will result in an error.
|
||||
|
||||
|
||||
If this per-collection limit is greater then the global `maxBooleanClauses` limit
|
||||
specified in `solr.xml`, it will have no effect, as that setting also limits the size
|
||||
of user specified boolean queries.
|
||||
|
@ -658,9 +656,6 @@
|
|||
enableRemoteStreaming - enables use of the stream.file
|
||||
and stream.url parameters for specifying remote streams.
|
||||
|
||||
enableStreamBody - This attribute controls whether streaming
|
||||
content from the HTTP parameter stream.body is allowed.
|
||||
|
||||
multipartUploadLimitInKB - specifies the max size (in KiB) of
|
||||
Multipart File Uploads that Solr will allow in a Request.
|
||||
|
||||
|
@ -679,12 +674,12 @@
|
|||
*** WARNING ***
|
||||
Before enabling remote streaming, you should make sure your
|
||||
system has authentication enabled.
|
||||
-->
|
||||
<requestParsers enableRemoteStreaming="true"
|
||||
enableStreamBody="true"
|
||||
|
||||
<requestParsers enableRemoteStreaming="false"
|
||||
multipartUploadLimitInKB="-1"
|
||||
formdataUploadLimitInKB="-1"
|
||||
addHttpRequestToContext="false"/>
|
||||
-->
|
||||
|
||||
<!-- HTTP Caching
|
||||
|
||||
|
@ -1278,17 +1273,19 @@
|
|||
|
||||
This example hooks in an update processor implemented using JavaScript.
|
||||
|
||||
See more about script update processor at https://lucene.apache.org/solr/guide/script-update-processor.html
|
||||
See more about the script update processor at http://wiki.apache.org/solr/ScriptUpdateProcessor
|
||||
-->
|
||||
<!--
|
||||
<updateRequestProcessorChain name="script">
|
||||
<processor class="solr.StatelessScriptUpdateProcessorFactory">
|
||||
<str name="script">update-script.js</str>
|
||||
<lst name="params">
|
||||
<str name="config_param">example config parameter</str>
|
||||
</lst>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
-->
|
||||
<updateRequestProcessorChain name="script">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<str name="script">update-script.js</str>
|
||||
<lst name="params">
|
||||
<str name="config_param">example config parameter</str>
|
||||
</lst>
|
||||
</processor>
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
|
||||
<!-- Response Writers
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
In order for this to be executed, it must be properly wired into solrconfig.xml; by default it is commented out in
|
||||
the example solrconfig.xml and must be uncommented to be enabled.
|
||||
|
||||
See https://lucene.apache.org/solr/guide/script-update-processor.html for more details.
|
||||
See http://wiki.apache.org/solr/ScriptUpdateProcessor for more details.
|
||||
*/
|
||||
|
||||
function processAdd(cmd) {
|
||||
|
||||
doc = cmd.solrDoc; // org.apache.solr.common.SolrInputDocument
|
||||
id = doc.getFieldValue("id");
|
||||
logger.warn("update-script#processAdd: id=" + id); // WARN level messages will show up in Solr Admin Logging UI
|
||||
logger.info("update-script#processAdd: id=" + id);
|
||||
|
||||
// Set a field value:
|
||||
// doc.setField("foo_s", "whatever");
|
||||
|
|
|
@ -88,7 +88,7 @@ This functionality is enabled by default, but can be disabled via a runtime para
|
|||
A configset is uploaded in a "trusted" mode if authentication is enabled and the upload operation is performed as an authenticated request. Without authentication, a configset is uploaded in an "untrusted" mode. Upon creation of a collection using an "untrusted" configset, the following functionality will not work:
|
||||
|
||||
* The XSLT transformer (`tr` parameter) cannot be used at request processing time.
|
||||
* If specified in the configset, the ScriptUpdateProcessorFactory will not initialize.
|
||||
* If specified in the configset, the StatelessScriptUpdateProcessor will not initialize.
|
||||
* Collections won't initialize if <lib> directives are used in the configset. (Note: Libraries added to Solr's classpath don't need the <lib> directive)
|
||||
|
||||
If you use any of these parameters or features, you must have enabled security features in your Solr installation and you must upload the configset as an authenticated user.
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
query-settings-in-solrconfig, \
|
||||
requestdispatcher-in-solrconfig, \
|
||||
update-request-processors, \
|
||||
script-update-processor, \
|
||||
codec-factory
|
||||
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
|
|
|
@ -144,9 +144,6 @@ _(raw; not yet edited)_
|
|||
|
||||
* SOLR-14972: The default port of prometheus exporter has changed from 9983 to 8989, so you may need to adjust your configuration after upgrade.
|
||||
|
||||
* SOLR-14067: StatelessScriptUpdateProcessorFactory moved to it's own /contrib/scripting/ package instead
|
||||
of shipping as part of Solr due to security concerns. Renamed to ScriptUpdateProcessorFactory for simpler name.
|
||||
|
||||
=== Upgrade Prerequisites in Solr 9
|
||||
|
||||
* Upgrade all collections in stateFormat=1 to stateFormat=2 *before* upgrading to Solr 9, as Solr 9 does not support the
|
||||
|
|
|
@ -1,286 +0,0 @@
|
|||
= Script Update Processor
|
||||
// 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.
|
||||
|
||||
The {solr-javadocs}/contrib/scripting/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.html[ScriptUpdateProcessorFactory] allows Java scripting engines to be used
|
||||
during Solr document update processing, allowing dramatic flexibility in
|
||||
expressing custom document processing logic before being indexed. It has hooks to the
|
||||
commit, delete, rollback, etc indexing actions, however add is the most common usage.
|
||||
It is implemented as an UpdateProcessor to be placed in an UpdateChain.
|
||||
|
||||
TIP: This used to be known as the _StatelessScriptingUpdateProcessor_ and was renamed to clarify the key aspect of this update processor is it enables scripting.
|
||||
|
||||
The script can be written in any scripting language supported by your JVM (such
|
||||
as JavaScript), and executed dynamically so no pre-compilation is necessary.
|
||||
|
||||
WARNING: Being able to run a script of your choice as part of the indexing pipeline is a really powerful tool, that I sometimes call the
|
||||
_Get out of jail free_ card because you can solve some problems this way that you can't in any other way. However, you are introducing some
|
||||
potential security vulnerabilities.
|
||||
|
||||
== Installing the ScriptingUpdateProcessor and Scripting Engines
|
||||
|
||||
The scripting update processor lives in the contrib module `/contrib/scripting`, and you need to explicitly add it to your Solr setup.
|
||||
|
||||
Java 11 and previous versions come with a JavaScript engine called Nashorn, but Java 12 will require you to add your own JavaScript engine. Other supported scripting engines like
|
||||
JRuby, Jython, Groovy, all require you to add JAR files.
|
||||
|
||||
Learn more about adding the `dist/solr-scripting-*.jar` file, and any other needed JAR files (depending on your scripting engine) into Solr's <<libs.adoc#lib-directories,Lib Directories>>.
|
||||
|
||||
== Configuration
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<updateRequestProcessorChain name="script">
|
||||
<processor class="org.apache.solr.scripting.update.ScriptUpdateProcessorFactory">
|
||||
<str name="script">update-script.js</str>
|
||||
</processor>
|
||||
<!-- optional parameters passed to script
|
||||
<lst name="params">
|
||||
<str name="config_param">example config parameter</str>
|
||||
</lst>
|
||||
-->
|
||||
<processor class="solr.LogUpdateProcessorFactory" />
|
||||
<processor class="solr.RunUpdateProcessorFactory" />
|
||||
</updateRequestProcessorChain>
|
||||
----
|
||||
|
||||
NOTE: The processor supports the defaults/appends/invariants concept for its config.
|
||||
However, it is also possible to skip this level and configure the parameters directly underneath the `<processor>` tag.
|
||||
|
||||
Below follows a list of each configuration parameters and their meaning:
|
||||
|
||||
`script`::
|
||||
The script file name. The script file must be placed in the `conf/ directory.
|
||||
There can be one or more "script" parameters specified; multiple scripts are executed in the order specified.
|
||||
|
||||
`engine`::
|
||||
Optionally specifies the scripting engine to use. This is only needed if the extension
|
||||
of the script file is not a standard mapping to the scripting engine. For example, if your
|
||||
script file was coded in JavaScript but the file name was called `update-script.foo`,
|
||||
use "javascript" as the engine name.
|
||||
|
||||
`params`::
|
||||
Optional parameters that are passed into the script execution context. This is
|
||||
specified as a named list (`<lst>`) structure with nested typed parameters. If
|
||||
specified, the script context will get a "params" object, otherwise there will be no "params" object available.
|
||||
|
||||
|
||||
== Script execution context
|
||||
|
||||
Every script has some variables provided to it.
|
||||
|
||||
`logger`::
|
||||
Logger (org.slf4j.Logger) instance. This is useful for logging information from the script.
|
||||
|
||||
`req`::
|
||||
{solr-javadocs}/core/org/apache/solr/request/SolrQueryRequest.html[SolrQueryRequest] instance.
|
||||
|
||||
`rsp`::
|
||||
{solr-javadocs}/core/org/apache/solr/response/SolrQueryResponse.html[SolrQueryResponse] instance.
|
||||
|
||||
`params`::
|
||||
The "params" object, if any specified, from the configuration.
|
||||
|
||||
== Examples
|
||||
|
||||
The `processAdd()` and the other script methods can return false to skip further
|
||||
processing of the document. All methods must be defined, though generally the
|
||||
`processAdd()` method is where the action is.
|
||||
|
||||
Here's a URL that works with the techproducts example setup demonstrating specifying
|
||||
the "script" update chain: `http://localhost:8983/solr/techproducts/update?commit=true&stream.contentType=text/csv&fieldnames=id,description&stream.body=1,foo&update.chain=script`
|
||||
which logs the following:
|
||||
|
||||
[source,text]
|
||||
----
|
||||
INFO: update-script#processAdd: id=1
|
||||
----
|
||||
|
||||
You can see the message recorded in the Solr logging UI.
|
||||
|
||||
=== Javascript
|
||||
|
||||
Note: There is a JavaScript example `update-script.js` as part of the `techproducts` configset.
|
||||
Check `solrconfig.xml` and uncomment the update request processor definition to enable this feature.
|
||||
|
||||
[source,javascript]
|
||||
----
|
||||
function processAdd(cmd) {
|
||||
|
||||
doc = cmd.solrDoc; // org.apache.solr.common.SolrInputDocument
|
||||
id = doc.getFieldValue("id");
|
||||
logger.info("update-script#processAdd: id=" + id);
|
||||
|
||||
// Set a field value:
|
||||
// doc.setField("foo_s", "whatever");
|
||||
|
||||
// Get a configuration parameter:
|
||||
// config_param = params.get('config_param'); // "params" only exists if processor configured with <lst name="params">
|
||||
|
||||
// Get a request parameter:
|
||||
// some_param = req.getParams().get("some_param")
|
||||
|
||||
// Add a field of field names that match a pattern:
|
||||
// - Potentially useful to determine the fields/attributes represented in a result set, via faceting on field_name_ss
|
||||
// field_names = doc.getFieldNames().toArray();
|
||||
// for(i=0; i < field_names.length; i++) {
|
||||
// field_name = field_names[i];
|
||||
// if (/attr_.*/.test(field_name)) { doc.addField("attribute_ss", field_names[i]); }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
function processDelete(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
function processMergeIndexes(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
function processCommit(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
function processRollback(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
function finish() {
|
||||
// no-op
|
||||
}
|
||||
----
|
||||
|
||||
=== Ruby
|
||||
Ruby support is implemented via the https://www.jruby.org/[JRuby] project.
|
||||
To use JRuby as the scripting engine, add `jruby.jar` to Solr.
|
||||
|
||||
Here's an example of a JRuby update processing script (note that all variables passed in require prefixing with `$`, such as `$logger`):
|
||||
|
||||
[source,ruby]
|
||||
----
|
||||
def processAdd(cmd)
|
||||
doc = cmd.solrDoc # org.apache.solr.common.SolrInputDocument
|
||||
id = doc.getFieldValue('id')
|
||||
|
||||
$logger.info "update-script#processAdd: id=#{id}"
|
||||
|
||||
doc.setField('source_s', 'ruby')
|
||||
|
||||
$logger.info "update-script#processAdd: config_param=#{$params.get('config_param')}"
|
||||
end
|
||||
|
||||
def processDelete(cmd)
|
||||
# no-op
|
||||
end
|
||||
|
||||
def processMergeIndexes(cmd)
|
||||
# no-op
|
||||
end
|
||||
|
||||
def processCommit(cmd)
|
||||
# no-op
|
||||
end
|
||||
|
||||
def processRollback(cmd)
|
||||
# no-op
|
||||
end
|
||||
|
||||
def finish()
|
||||
# no-op
|
||||
end
|
||||
----
|
||||
|
||||
==== Known issues
|
||||
|
||||
The following in JRuby does not work as expected for some reason, though it does work properly in JavaScript:
|
||||
|
||||
[source,ruby]
|
||||
----
|
||||
# $logger.info "update-script#processAdd: request_param=#{$req.params.get('request_param')}"
|
||||
# $rsp.add('script_processed',id)
|
||||
----
|
||||
|
||||
=== Groovy
|
||||
|
||||
Add JARs from a Groovy distro's `lib/` directory to Solr. All JARs from
|
||||
Groovy's distro probably aren't required, but more than just the main `groovy.jar`
|
||||
file is needed (at least when this was tested using Groovy 2.0.6)
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
def processAdd(cmd) {
|
||||
doc = cmd.solrDoc // org.apache.solr.common.SolrInputDocument
|
||||
id = doc.getFieldValue('id')
|
||||
|
||||
logger.info "update-script#processAdd: id=" + id
|
||||
|
||||
doc.setField('source_s', 'groovy')
|
||||
|
||||
logger.info "update-script#processAdd: config_param=" + params.get('config_param')
|
||||
|
||||
logger.info "update-script#processAdd: request_param=" + req.params.get('request_param')
|
||||
rsp.add('script_processed',id)
|
||||
}
|
||||
|
||||
def processDelete(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
def processMergeIndexes(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
def processCommit(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
def processRollback(cmd) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
def finish() {
|
||||
// no-op
|
||||
}
|
||||
----
|
||||
|
||||
=== Python
|
||||
Python support is implemented via the https://www.jython.org/[Jython] project.
|
||||
Add the *standalone* `jython.jar` (the JAR that contains all the dependencies) into Solr.
|
||||
|
||||
[source,python]
|
||||
----
|
||||
def processAdd(cmd):
|
||||
doc = cmd.solrDoc
|
||||
id = doc.getFieldValue("id")
|
||||
logger.info("update-script#processAdd: id=" + id)
|
||||
|
||||
def processDelete(cmd):
|
||||
logger.info("update-script#processDelete")
|
||||
|
||||
def processMergeIndexes(cmd):
|
||||
logger.info("update-script#processMergeIndexes")
|
||||
|
||||
def processCommit(cmd):
|
||||
logger.info("update-script#processCommit")
|
||||
|
||||
def processRollback(cmd):
|
||||
logger.info("update-script#processRollback")
|
||||
|
||||
def finish():
|
||||
logger.info("update-script#finish")
|
||||
----
|
|
@ -283,7 +283,7 @@ What follows are brief descriptions of the currently available update request pr
|
|||
|
||||
{solr-javadocs}/core/org/apache/solr/update/processor/SignatureUpdateProcessorFactory.html[SignatureUpdateProcessorFactory]:: Uses a defined set of fields to generate a hash "signature" for the document. Useful for only indexing one copy of "similar" documents.
|
||||
|
||||
{solr-javadocs}/contrib/scripting/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.html[ScriptUpdateProcessorFactory]:: An processor that enables the use of update processors implemented as scripts. Learn more at the <<script-update-processor.adoc#script-update-processor,script update processor>> page.
|
||||
{solr-javadocs}/core/org/apache/solr/update/processor/StatelessScriptUpdateProcessorFactory.html[StatelessScriptUpdateProcessorFactory]:: An update request processor factory that enables the use of update processors implemented as scripts.
|
||||
|
||||
{solr-javadocs}/core/org/apache/solr/update/processor/TemplateUpdateProcessorFactory.html[TemplateUpdateProcessorFactory]:: Allows adding new fields to documents based on a template pattern. This update processor can also be used at runtime (without defining it in `solrconfig.xml`), see the section <<templateupdateprocessorfactory>> below.
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ public class UpdateProcessorTestBase extends SolrTestCaseJ4 {
|
|||
/**
|
||||
* Convenience method for building up SolrInputDocuments
|
||||
*/
|
||||
protected final SolrInputDocument doc(SolrInputField... fields) {
|
||||
final SolrInputDocument doc(SolrInputField... fields) {
|
||||
SolrInputDocument d = new SolrInputDocument();
|
||||
for (SolrInputField f : fields) {
|
||||
d.put(f.getName(), f);
|
||||
|
@ -162,7 +162,7 @@ public class UpdateProcessorTestBase extends SolrTestCaseJ4 {
|
|||
/**
|
||||
* Convenience method for building up SolrInputFields with default boost
|
||||
*/
|
||||
protected final SolrInputField f(String name, Object... values) {
|
||||
final SolrInputField f(String name, Object... values) {
|
||||
return field(name, values);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue