让我们来看下面的例子. 假设我们数据库中的表结构如下:
This is a relational model of the same schema that Solr currently ships with. 我们使用这个例子来为我们的DataImportHandler建data-config.xml。 我们已经使用这个结构在HSQLDB上建立了一个数据库. 好,现在开始了, 跟着下面的步骤走:
下载 example-solr-home.jar 并使用 jar解压 jar -xvf example-solr-home.jar ,解压到你的本地系统. 这个jar文件包含了一个完整的solrhome(里面的配置文件很齐全了)和一个RSS的例子。它也包含了一个hssqldb数据库的例子.
<dataConfig>
<dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" />
<document>
<entity name="item" query="select * from item">
<entity name="feature" query="select description as features from feature where item_id='${item.ID}'"/>
<entity name="item_category" query="select CATEGORY_ID from item_category where item_id='${item.ID}'">
<entity name="category" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"/>
</entity>
</entity>
</document>
</dataConfig> 使用“增量导入”命令
<dataConfig>
<dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" />
<document name="products">
<entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
<entity name="feature" pk="ITEM_ID" query="select description as features from feature where item_id='${item.ID}'"> </entity>
<entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'">
<entity name="category" pk="ID" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"> </entity>
</entity>
</entity>
</document>
</dataConfig>
注意到item实体的 属性deltaquery了吗,它包含了一个能够查出最近更新的sql语句。注意,变量{dataimporter.last_index_time} 是DataImporthandler传过来的变量,我们叫它时间戳,它指出“完全导入”或者“部分导入”的最后运行时间。你可以在data-config.xml文件中的sql的任何地方使用这个变量,它将在processing这个过程中被赋值。
注意
deltaQuery="select id from item where id in (select item_id as id from feature where last_modified > '${dataimporter.last_index_time}') or id in (select item_id as id from item_category where item_id in (select id as item_id from category where last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}'"
<dataConfig>
<dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" />
<document>
<entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
<entity name="feature" pk="ITEM_ID" query="select DESCRIPTION as features from FEATURE where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}"/>
<entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}">
<entity name="category" pk="ID" query="select DESCRIPTION as cat from category where ID = '${item_category.CATEGORY_ID}'" deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}"/>
</entity>
</entity>
</document>
</dataConfig>
useSolrAddSchema(可选): Set it's value to 'true' if the xml that is fed into this processor has the same schema as that of the solr add xml. No need to mention any fields if it is set to true.
public abstract class Transformer {
/** * The input is a row of data and the output has to be a new row.
* * @param context The current context
* @param row A row of data
* @return The changed data.
It must be a Map if it returns
* only one row or if there are multiple rows to be returned it must
* be a List
>
*/
public abstract Object transformRow(Map row, Context context);
}
Context 是一个抽象的类,它提供上下文关系,这可能在处理数据的时候要用到。
另外,类Foo,可以选择不不实现这个抽象类,而只需要下面这个方法
public Object transformRow(Map row)
So there is no compile-time dependency on the DataImportHandler API
它的配置是灵活的。它允许用户向标签entity和field提供任意的属性。tool将会读取数据,并将它传给实现类。如果Transformer需要额外的的信息,它可以从context中取得。
template : 模板字符串。上面的例子中有两个占位符,‘${e.name}和${eparent.surname}’。 In the above example there are two placeholders '${e.name}' and '${eparent.surname}' . 两个值都必须存在,否则这个模板将不会起作用。
package foo; public class TrimTransformer extends Transformer { public Map transformRow(Map row, Context context) { List
> fields = context.getAllEntityFields(); for (Map field : fields) { // Check if this field has trim="true" specified in the data-config.xml String trim = field.get("trim"); if ("true".equals(trim)) { // Apply trim on this field String columnName = field.get("column"); // Get this field's value from the current row String value = row.get(columnName); // Trim and put the updated value back in the current row if (value != null) row.put(columnName, value.trim()); } } return row; } }
如果域是多值的,那么返回值将会是一个list而不是单单一个对象,而且需要被恰当的处理。你可以将DataImprotHandler打包成一个jar包,然后再扩展Transformer和Context。
应该说,这是SqlEntityProcessor的一个扩展,这个处理器通过缓存一些行,来减少数据库查询。它几乎对根实体没有用,因为这个实体中只有一个sql语句被执行了。
Example 1.
<entity name="x" query="select * from x">
<entity name="y" query="select * from y where xid=${x.id}" processor="CachedSqlEntityProcessor">
</entity>
<entity>
这个例子的用法跟下面的是一样的,一个查询被执行完,它的结果被存储起来,下次这个查询再被执行的的时候,它将会从缓存中取出结果并返回。
Example 2:
<entity name="x" query="select * from x">
<entity name="y" query="select * from y" processor="CachedSqlEntityProcessor" where="xid=x.id">
</entity>
<entity>
这个例子跟前一个的区别在于属性‘where’。这个例子中,查询语句将从表中取回所有的数据,并把他们都放在缓存中。其中的关键就在域 属性‘where’。缓存使用y中的xid作为键值,实体被查询的时候x.id的值就会被计算出来,我们首先会在缓存中找匹配的数据,接着返回。
public abstract class DataSource {
/** * Initializes the DataSource with the Context and * initialization properties. *
* This is invoked by the DataImporter after creating an
* instance of this class.
* * @param context * @param initProps
*/
public abstract void init(Context context, Properties initProps);
/** * Get records for the given query.The return type depends on the * implementation .
* * @param query The query string. It can be a SQL for JdbcDataSource or a URL
* for HttpDataSource or a file location for FileDataSource or a custom
* format for your own custom DataSource.
* @return Depends on the implementation. For instance JdbcDataSource returns
* an Iterator>
*/
public abstract T getData(String query);
/** * Cleans up resources of this DataSource after use. */
public abstract void close();
}
它必须在数据源的定义部分被配置。
<dataSource type="com.foo.FooDataSource" prop1="hello"/>
JdbcdataSource
这个是默认的,它的声明如下:
public class JdbcDataSource extends DataSource>>
它可以一条一条的遍历数据库,每一行数据被当作一个Map。
HttpDataSource
XPathEntityProcessor使用这个数据源 . 它的声明如下:
public class HttpDataSource extends DataSource FileDataSource
这个很像HttpDataSource . 它的声明如下:
public class FileDataSource extends DataSource
The attributes are:
basePath: (可选的) ,得到所需要的值时必须的基本路径。
encoding: (可选的)当文件编码跟平台编码不一样的时候,应当设定这个值。
Boosting , Skipping documents(提高文档的得分,或者跳过文档)
我们还可以在运行的时候提高一个文档的得分,或者跳过某一个特定的文档。
可以通过自定义转化器,增加一个属性,并将它设为true,这样就可以跳过这个文档了。可以通过,增加一个属性docBoost ,属性是文档的评分的这种方式给文档打分。Write a custom Transformer to add a value $skipDoc with a value 'true' to skip that document. To boost a document with a given value add $docBoost with the boost value
formatDate : 它可以像这样去使用,'${dataimporter.functions.formatDate(item.ID, yyyy-MM-dd HH:mm)}' 。它的第一个参数是一个合法的变量,第二个参数是一种时间格式(这里使用的格式工具是SimpledateFormat),The first argument can be a valid value from the VariableResolver and the second cvalue can be a a format string (use SimpledateFormat) . 它可以是一个经过计算的值,它使用solr的时间表示方式。(要注意,它必须被单引号括起来