solr搜索引擎ScriptTransformer(脚本转换器)


image.png


        今天在使用搜索引擎solr导入数据的时候遇到一个问题,有些字段从数据库中取出来不是我们想要的格式,而是想把原始数据转化成其他的方式存储在索引中,所以强大的solr早就为我们想好了,Data Import Request Handler中提供了一系列的数据转换器。数据转换器有很多种,RegexTransformer,ScriptTransformer,DateFormatTransformer,NumberFormatTransformer,TemplateTransformer,HTMLStripTransformer,ClobTransformer,LogTransformer,Transformers Example,Writing Custom Transformers,今天我着重介绍一下ScriptTransformer(脚本转换器)。

        ScriptTransformer脚本转换器采用的是javascript脚本语言来转换数据,那么还需要懂一些js了,先来看看官方文档,讲解的还算齐全。https://wiki.apache.org/solr/DataImportHandler#ScriptTransformer


ScriptTransformer

It is possible to write transformers in Javascript or any other scripting language supported by Java. You must use Java 6 to use this feature.

<dataConfig>
        <script><![CDATA[
                function f1(row)        {
                    row.put('message', 'Hello World!');
                    return row;
                }
        ]]></script>
        <document>
                <entity name="e" pk="id" transformer="script:f1" query="select * from X">
                ....
                </entity>
        </document>
</dataConfig>


Another more complex example

<dataConfig>
        <script><![CDATA[
                function CategoryPieces(row)    {
                    var pieces = row.get('category').split('/');
                    var arr = new java.util.ArrayList();
                    for (var i=0; i<pieces.length; i++) {
                       arr.add(pieces[i]);
                    }
                    row.put('categorypieces', arr);
                    row.remove('category');
                    return row;
                }
        ]]></script>
        <document>
                <entity name="e" pk="id" transformer="script:CategoryPieces" query="select * from X">
                ....
                </entity>
        </document>
</dataConfig>


  • You can put a script tag inside the dataConfig node. By default, the language is assumed to be Javascript. In case you're using another language, specify on the script tag with attribute 'language="MyLanguage"' (must be supported by java 6)

  • Write as many transformer functions as you want to use. Each such function must accept a row variable corresponding to Map<String, Object> and return a row (after applying transformations)

  • To remove entries from the row use row.remove(keyname);

  • To add multiple entries for a single field use var arr = new java.util.ArrayList(), you can't use a JavaScript array.

  • Documentation for the Java Map object Java 6 Map

  • Documentation for the Java ArrayList object Java 6 ArrayList

  • Make an entity use a function by specifying transformer="script:<function-name>" in the entity node.

  • In the above data-config, the javascript function f1 will be executed once for each row returned by entity e.

  • The semantics of execution is same as that of a java transformer. The method can have two arguments as in 'transformRow(Map<String,Object> , Context context) in the abstract class 'Transformer' . As it is javascript the second argument may be omittted and it still works.


稍微翻译一下上面这段话:

1:你可以把脚本标记在dataConfig节点。默认情况下,语言被认为是Javascript。如果你使用另一种语言时,指定的脚本标记属性 'language="MyLanguage"(必须支持java 6)   

2:你可以编写尽可能多你想去使用的转换函数。

3:从一行里面删除条目使用row.remove(keyname); 

4:为单个字段添加多个条目使用var arr = new java.util.ArrayList(),,你不能使用一个JavaScript数组。 

5:Java Map 的文档Java 6 Map 

6:Java ArrayList 的文档Java 6 ArrayList   

7:在实体节点添加transformer="script:<function-name>" 属性来使用一个函数。   

8:在上面的data-config,javascript函数f1将会为每一行执行一次返回的实体。   

9:执行的语义和java转化器相同。在抽象类Transformer中这个方法可以有两个参数放在transformRow(Map<String,Object> , Context context)里。如果是javascript,第二个参数可能被忽略但是还是可以正常工作的。


很简单,使用方法都在里面写了。。。

需要注意的是,函数将会在每个entity下面的字段中执行,所以关联模型中,注意关联的模型的entity需要单独的转换器,而且用row.put()添加字段时,字段要与现在managed-schema中进行声明。但是solr有个坑。。。有的时候我们需要保留关联模型的数据结构,找了很久都没找到怎么实现:比如下面的json

{
    "name": "希希",
    "books": [
        {
            "id": 1,
            "name": "java编程思想"
        },
        {
            "id": 2,
            "name": "细说php"
        }
    ]
}

solr没有办法在一个字段里面保存一个对象,好像managed-schema里面也不能这么这么声明,想了一下,想把它转化为json字符串然后保存到这个字段里,但是这样感觉冗余信息会比较多,然后干脆自己拼接字符串了

比如上面的,这样也不会影响索引,又能节省空间,但是数据取出来之后要还原一下数据。

{
    "name": "希希",
    "books": ["1_java编程思想","2_细说php"]
}


本文 暂无 评论

Top