• solr 高级进阶,解决问题


    一、多表、多数据源 数据导入的问题
    之前介绍过通过data-config.xml 导入数据的问题,实际开发过程中可能会遇到多表、甚至是多数据源的问题,以下我根据实际业务场景说下该如何解决该问题。
    只需要,更改data-config.xml的写法就行了。
    <dataConfig>
    <!-- <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_studio" user="yxj" password="yxj@2015" /> -->

    <dataSource name ="db_yxj_content" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_content" user="xxx" password="xxx" />
    <dataSource name ="db_yxj_user" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_user" user="xxx" password="xxx" />
    <document name = "insert_test">
    <entity name="video" transformer="DateFormatTransformer"
    query="SELECT
    CONCAT(v.vdoid,'video') as id,
    v.vdoid AS vdoid,
    v.catid AS catid,
    v.catids AS catids,
    v.proid AS proid,
    v.title AS title,
    ifnull(v.content, '') AS content,
    v.num AS num,
    v.vdo_type AS vdoType,
    v.play_url AS playUrl,
    LEFT (
    FROM_UNIXTIME(v.publish_time),
    10
    ) AS publishTime,
    v. STATUS AS STATUS,
    v.keywords AS keywords,
    v.coverpic_url AS coverpicUrl,
    v.end_time AS endTime,
    v.start_time AS startTime,
    FROM_UNIXTIME(
    v.update_time,
    '%Y-%m-%d %H:%m:%s'
    ) AS updateTime,
    v.isTop AS isTop,
    parent_id AS parentId,
    p.proid AS proid,
    ifnull(p. NAME, '') AS proName,
    ifnull(p.org, '') AS proOrg,
    ifnull(p.title, '') AS proTitle,
    ifnull(p.department, '') AS proDepartment,
    ifnull(CONCAT(p. NAME, p.title, ' ', p.org), '') AS tempContent
    FROM
    db_yxj_content.t_video v
    LEFT JOIN db_yxj_user.t_professor p ON v.proid = p.proid
    WHERE
    v. STATUS = 0
    AND (
    (
    v.vdo_type = 1
    AND (
    classify_flag = 2
    OR length(v.play_url) > 0
    )
    )
    OR v.vdo_type = 10
    )">
    <field column='publishTime' dateTimeFormat='yyyy-MM-dd' />
    <field column='updateTime' dateTimeFormat='yyyy-MM-dd HH:mm:ss' />
    </entity>
    </document>

    </dataConfig>
    dataSource : 数据源的配置,这里用的是mysql ,如果是多数据源需要根据数据库的连接属性,配置多个相对应的dataSource
    sql: document 下的entity 中 sql 的写法,需要把 数据库名称写上,如上写法 数据库名.表名:db_yxj_content.t_video

    二、全量导入、增量导入的问题


    之前介绍过通过页面操作数据导入的方法。接下来介绍一下 ,如何配置 增量以及全量导入。
    1.全量导入
    全量导入很简单,只要成功配置好data-config.xml 就可以通过点击Execute 按钮 完成全量导入。
    2.增量导入
    这里主要介绍下 增量导入的问题。顾名思义,增量导入即只导入部分数据,这在实际开发中一定是用的到的,因为在我们上线前,可以把数据一次性导入solr完成数据同步,但是上线后新产生的数据或者某些数据被删除或者修改,则需要动过增量导入的方式同步到solr中,data-config.xml配置如下:
    <dataConfig>
    <!-- <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_studio" user="yxj" password="yxj@2015" /> -->

    <dataSource name ="db_yxj_content" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_content" user="xxx" password="xxx" />
    <dataSource name ="db_yxj_user" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_user" user="xxx" password="xxx" />
    <document name = "insert_test">
    <entity name="video" transformer="DateFormatTransformer"
    query="SELECT
    CONCAT(v.vdoid,'video') as id,
    v.vdoid AS vdoid,
    v.catid AS catid,
    v.catids AS catids,
    v.proid AS proid,
    v.title AS title,
    ifnull(v.content, '') AS content,
    v.num AS num,
    v.vdo_type AS vdoType,
    v.play_url AS playUrl,
    LEFT (
    FROM_UNIXTIME(v.publish_time),
    10
    ) AS publishTime,
    v. STATUS AS STATUS,
    v.keywords AS keywords,
    v.coverpic_url AS coverpicUrl,
    v.end_time AS endTime,
    v.start_time AS startTime,
    FROM_UNIXTIME(
    v.update_time,
    '%Y-%m-%d %H:%m:%s'
    ) AS updateTime,
    v.isTop AS isTop,
    parent_id AS parentId,
    p.proid AS proid,
    ifnull(p. NAME, '') AS proName,
    ifnull(p.org, '') AS proOrg,
    ifnull(p.title, '') AS proTitle,
    ifnull(p.department, '') AS proDepartment,
    ifnull(CONCAT(p. NAME, p.title, ' ', p.org), '') AS tempContent
    FROM
    db_yxj_content.t_video v
    LEFT JOIN db_yxj_user.t_professor p ON v.proid = p.proid
    WHERE
    v. STATUS = 0
    AND (
    (
    v.vdo_type = 1
    AND (
    classify_flag = 2
    OR length(v.play_url) > 0
    )
    )
    OR v.vdo_type = 10
    )"

    deltaImportQuery ="SELECT
    CONCAT(v.vdoid,'video') as id,
    v.vdoid AS vdoid,
    v.catid AS catid,
    v.catids AS catids,
    v.proid AS proid,
    v.title AS title,
    ifnull(v.content, '') AS content,
    v.num AS num,
    v.vdo_type AS vdoType,
    v.play_url AS playUrl,
    LEFT (
    FROM_UNIXTIME(v.publish_time),
    10
    ) AS publishTime,
    v. STATUS AS STATUS,
    v.keywords AS keywords,
    v.coverpic_url AS coverpicUrl,
    v.end_time AS endTime,
    v.start_time AS startTime,
    FROM_UNIXTIME(
    v.update_time,
    '%Y-%m-%d %H:%m:%s'
    ) AS updateTime,
    v.isTop AS isTop,
    parent_id AS parentId,
    p.proid AS proid,
    ifnull(p. NAME, '') AS proName,
    ifnull(p.org, '') AS proOrg,
    ifnull(p.title, '') AS proTitle,
    ifnull(p.department, '') AS proDepartment,
    ifnull(CONCAT(p. NAME, p.title, ' ', p.org), '') AS tempContent
    FROM
    db_yxj_content.t_video v
    LEFT JOIN db_yxj_user.t_professor p ON v.proid = p.proid
    WHERE
    v.vdoid = '${dih.delta.id}'"

    deltaQuery ="SELECT
    v.vdoid AS id
    FROM
    db_yxj_content.t_video v
    LEFT JOIN db_yxj_user.t_professor p ON v.proid = p.proid
    WHERE
    v. STATUS = 0
    AND (
    (
    v.vdo_type = 1
    AND (
    classify_flag = 2
    OR length(v.play_url) > 0
    )
    )
    OR v.vdo_type = 10
    )
    AND ( FROM_UNIXTIME(
    v.update_time,
    '%Y-%m-%d %H:%m:%s'
    ) > '${dataimporter.video.last_index_time}'
    OR
    FROM_UNIXTIME(
    v.publish_time,
    '%Y-%m-%d %H:%m:%s'
    ) > '${dataimporter.video.last_index_time}'
    )
    ">
    <field column='publishTime' dateTimeFormat='yyyy-MM-dd' />
    <field column='updateTime' dateTimeFormat='yyyy-MM-dd HH:mm:ss' />
    </entity>

    </document>

    </dataConfig>
    网上对以下字段的解释很多,我这里说下自己的理解:
    query:全量查询执行的sql ,所以一般不需要带上条件
    deltaImportQuery :增量插入,这里需要带上条件,条件的写法很固定,需要通过 deltaQuery 执行后得到的结果 进行数据插入
    deltaQuery :主要服务与deltaImportQuery 在做增量插入的时候,通过该sql 查询出需要增量数据的ID,有两点需要注意,1~这里必须查出ID并且只能叫ID 2~这个sql 的条件的写法也很固定, '${dataimporter.video.last_index_time}' 指的是dataimport.properties 中的 时间,这个时间是指,最后一次执行增量或者全量导入的时间,只要数据发生变化了,dataimport.properties 中的时间会自动更新。

    通过以上三个字段的介绍,应该能明白,solr的增量导入 依据的其实就是,数据库的变化(前提是数据库中需要有update_time 字段,每次数据发生变化要更新该字段,我这里的update_time 是long 类型的unix十进制时间所以写法,需要根据自己实际情况改变)比较最后一次改变数据的时间,做增量数据更改。

    三、一个库 中多个搜索的问题
    实际开发过程中,我们不可能为每一个搜索都创建一个core ,我们的数据大都放到同一个core 中,这样便于维护。那么怎么保证搜索视频的时候不会把文章搜索出来呢。其实很简单,还是看data-config.xml配置如下:
    <dataConfig>
    <!-- <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_studio" user="yxj" password="yxj@2015" /> -->

    <dataSource name ="db_yxj_content" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_content" user="xxx" password="xxx" />
    <dataSource name ="db_yxj_user" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://123.59.41.168:3306/db_yxj_user" user="xxx" password="xxx" />
    <document name = "insert_test">
    <entity name="video" transformer="DateFormatTransformer"
    query="SELECT
    CONCAT(v.vdoid,'video') as id,
    v.vdoid AS vdoid,
    v.catid AS catid,
    v.catids AS catids,
    v.proid AS proid,
    v.title AS title,
    ifnull(v.content, '') AS content,
    v.num AS num,
    v.vdo_type AS vdoType,
    v.play_url AS playUrl,
    LEFT (
    FROM_UNIXTIME(v.publish_time),
    10
    ) AS publishTime,
    v. STATUS AS STATUS,
    v.keywords AS keywords,
    v.coverpic_url AS coverpicUrl,
    v.end_time AS endTime,
    v.start_time AS startTime,
    FROM_UNIXTIME(
    v.update_time,
    '%Y-%m-%d %H:%m:%s'
    ) AS updateTime,
    v.isTop AS isTop,
    parent_id AS parentId,
    p.proid AS proid,
    ifnull(p. NAME, '') AS proName,
    ifnull(p.org, '') AS proOrg,
    ifnull(p.title, '') AS proTitle,
    ifnull(p.department, '') AS proDepartment,
    ifnull(CONCAT(p. NAME, p.title, ' ', p.org), '') AS tempContent
    FROM
    db_yxj_content.t_video v
    LEFT JOIN db_yxj_user.t_professor p ON v.proid = p.proid
    WHERE
    v. STATUS = 0
    AND (
    (
    v.vdo_type = 1
    AND (
    classify_flag = 2
    OR length(v.play_url) > 0
    )
    )
    OR v.vdo_type = 10
    )">
    <field column='publishTime' dateTimeFormat='yyyy-MM-dd' />
    <field column='updateTime' dateTimeFormat='yyyy-MM-dd HH:mm:ss' />
    </entity>

    <entity name="article" transformer="DateFormatTransformer"
    query="SELECT
    CONCAT(art.artid,'article') as id,
    art.artid as artid,
    art.art_date as artDate,
    art.num as num,
    art.title as artTitle,
    art.brief as brief,
    art.minpic_url as minpicUrl,
    art.content as artContent,
    art.update_time as artUpdateTime
    FROM
    db_yxj_content.t_article art
    WHERE
    art. STATUS = 0">
    <field column='updateTime' dateTimeFormat='yyyy-MM-dd HH:mm:ss' />
    </entity>
    </document>

    </dataConfig>
    如上,可以看到document 下的有多个entity ,其实每个entity 代表的都是不同的数据组。不过虽然数据都被用组分开了,但是查询的时候 还会出现,另外一个问题,那就是 ,通过模糊查询把,文章视频都查了出来,但是我们这次查询其实只是想查询到,视频数据或者文章数据,那么该如何避免该问题呢?
    如下:文章和视频都被查询了出来

    通过为设置copy字段,并创建索引的方式,配置managed-schema 如下:

    <!-- t_video 普通字段不需要建立索引-->
    <field name="vdoid" type="plong" indexed="true" stored="true"/>
    <field name="catid" type="plong" indexed="false" stored="true"/>
    <field name="catids" type="string" indexed="false" stored="true"/>
    <field name="proid" type="plong" indexed="false" stored="true"/>
    <field name="title" type="string" indexed="false" stored="true"/>
    <field name="num" type="pint" indexed="false" stored="true"/>
    <field name="publishTime" type="pdate" indexed="false" stored="true"/>
    <field name="coverpicUrl" type="string" indexed="false" stored="true"/>
    <field name="endTime" type="plong" indexed="false" stored="true"/>
    <field name="updateTime" type="pdate" indexed="false" stored="true"/>
    <field name="content" type="text_general" indexed="false" stored="true"/>
    <field name="playUrl" type="string" indexed="false" stored="true"/>
    <field name="vdoType" type="pint" indexed="false" stored="true"/>
    <field name="startTime" type="plong" indexed="false" stored="true"/>
    <field name="parentId" type="string" indexed="false" stored="true"/>
    <field name="keywords" type="string" indexed="false" stored="true"/>

    <!-- guan lian -->
    <field name="tempContent" type="string" indexed="false" stored="true"/>
    <field name="proName" type="string" indexed="false" stored="true"/>
    <field name="proOrg" type="string" indexed="false" stored="true"/>
    <field name="proDepartment" type="string" indexed="false" stored="true"/>
    <field name="proTitle" type="string" indexed="false" stored="true"/>
    <!-- copyField就引出了solr的一个全文检索的概念,如果我要实现一个搜索,而我要搜索的属性有很多个那么应该使用如下配置方法-->
    <copyField source="title" dest="text_video"/>
    <copyField source="proName" dest="text_video"/>
    <copyField source="proOrg" dest="text_video"/>
    <copyField source="content" dest="text_video"/>
    <!-- 搜索用建立索引 不需要返回-->
    <field name="text_video" type="text_ik" indexed="true" stored="false" multiValued="true" />



    <!-- t_article 普通字段不需要建立索引-->
    <field name="artid" type="plong" indexed="true" stored="true" />
    <field name="artDate" type="string" indexed="false" stored="true"/>
    <field name="artNum" type="pint" indexed="false" stored="true"/>
    <field name="artTitle" type="string" indexed="false" stored="true"/>
    <field name="brief" type="string" indexed="false" stored="true"/>
    <field name="minpicUrl" type="string" indexed="false" stored="true"/>
    <field name="artContent" type="text_general" indexed="false" stored="true"/>
    <field name="artUpdateTime" type="plong" indexed="false" stored="true"/>
    <!-- copyField就引出了solr的一个全文检索的概念,如果我要实现一个搜索,而我要搜索的属性有很多个那么应该使用如下配置方法-->
    <copyField source="artTitle" dest="text_article"/>
    <copyField source="brief" dest="text_article"/>
    <copyField source="artContent" dest="text_article"/>
    <!-- 搜索用建立索引 不需要返回-->
    <field name="text_article" type="text_ik" indexed="true" stored="true" multiValued="true" />
    通过以上配置。可以看到,我把需要索引的字段,通过copyField 的方式 copy 到 新建立的一个field中,如上配置中分别是text_video、text_article,我把这两个file 叫做搜索域,并且根据实际情况设置 type 我用了IK分词器,设置stored 是否返回,为这里只是为了测试设置成true,为了减少开销可以设置为false。并且只对搜索域字段创建索引,可以看到其他字段我都没有创建索引,因为我只会对该字段进行搜索,我觉得这样有两点好处 1.避免不必要的索引开销 2. 规避不需要的域的数据。
    okay~这样基本上,不管是导入还是查询,都能运用到日常的生产开发中了。

    四、 定时创建全量索引和增量索引 ,以及DIH的配置 参数相关
    好,各位有没有发现,如上问题解决完后,还是不能真正的投产,因为,我们不可能通过solr 的管理页面,每次去认为的维护数据,你可能想到了,生产发布前,进行全量导入,之后数据的维护通过定时任务或者,每次对数据增删改查的时候,通过接口对solr进行同步维护。以上肯定可以解决关于数据维护的问题,但是成本太高了,如此优秀的solr 肯定有办法帮你解决这个问题。那就是 solr本身定时器的使用,不过有点繁琐,solr 5以后的版本 定时器的维护也停止了,所以现有的jar包没办法兼容solr7的定时器的使用。需要对jar 进行改造,改造后的jar 可以在如下链接下载:
    https://download.csdn.net/download/csdn_fan321/10222478
    现在说下如何使用该jar包。这里默认你看过我之前写的博客。一下路径都是按照之前的配置来的。
    1.首先需要在E:solrhome 下创建文件夹conf ,并且创建文件dataimport.properties
    写入如下内容,我只用到了 ,增量维护的部分,全量可以定时导入的,具体可以到网上看下,只是配置问题。

    #################################################
    # #
    # dataimport scheduler properties #
    # #
    #################################################

    # to sync or not to sync
    # 1 - active; anything else - inactive
    syncEnabled=1

    # which cores to schedule
    # in a multi-core environment you can decide which cores you want syncronized
    # leave empty or comment it out if using single-core deployment
    # 你的核心 名称,多个用‘,’隔开
    syncCores=testCore

    # solr server name or IP address
    # [defaults to localhost if empty]
    server=localhost

    # solr server port
    # [defaults to 80 if empty]
    # 你得solr 的启动的端口号
    port=8888

    # application name/context
    # [defaults to current ServletContextListener's context (app) name]
    # webapp的名称
    webapp=solr

    # URL params [mandatory]
    # remainder of URL
    # 请求的参数
    params=/dataimport?command=delta-import&clean=false&commit=true&optimize=false&wt=json&indent=on&verbose=false&debug=true

    # schedule interval
    # number of minutes between two runs
    # [defaults to 30 if empty]
    # 执行的频率,分钟
    interval=1


    如上配置,简单易懂,我对请求参数 即DIH的配置 单独讲解下,和页面上复选框其实是一一对应的。
     
    entity:entity是document下面的标签(data-config.xml)。使用这个参数可以有选择的执行一个或多个entity   。使用多个entity参数可以使得多个entity同时运行。如果不选择此参数那么所有的都会被运行。
     clean:选择是否要在索引开始构建之前删除之前的索引,默认为true
     commit:选择是否在索引完成之后提交。默认为true
     optimize:是否在索引完成之后对索引进行优化。默认为true
    debug:是否以调试模式运行,适用于交互式开发(interactive development mode)之中。
    indent:on或者true是打开。false 关闭。返回的数据 是 缩进的。
    2.tomcat 的 webappssolrWEB-INF 下 web.xml ,web-app标签下 添加如下代码:
    <listener>
    <listener-class>org.apache.solr.handler.dataimport.scheduler.ApplicationListener</listener-class>
    </listener>
    3.需要将刚才下载的jar(solr-dataimportscheduler-1.1.0.jar) 放入到.tomcat 的 webappssolrWEB-INFlib 下
    4.重启tomcat ,你能看到

    定时器被执行了,影响的行数为0
    duang~ 搞定

    五、关于ID字段 如何避免同一核中多个搜索避免ID重复的问题
    还有个问题在这里跟大家分享下,就是在solr实际使用中,发现 ID 字段是必须设置的。就是说每个entity 中的数据,都必须有ID ,如果不指定,那么会自动添加UUID 。这个ID 也非常重要,在做数据导入的时候,就是根据ID字段 鉴别记录是否存在,如果存在solr不会反复插入数据,他会在之前的数据上更新替换,这也是 增量导入时候 为了防止数据重复添加的依据,那么问题来了。同一个core 下 多个entity 的情况下,每个entity 都有ID这个字段,那么极有可能出现ID冲突,因为使用mysql的用户大部分都是用的mysql 的自增字段做的ID,那么就会出现在增量更新文章的时候,发现把相同ID的视频记录覆盖了的情况,这是我们必须避免的问题。我采用的是 别名的方式 回避这个问题。其实之前data-config.xml配置文件中的 sql 已经体现了。举例如下:
    正常sql :select id,userName,sex from user;
    优化的sql: select CONCAT(u.id,'user') as id,u.id as uid,u.userName,u.sex from user u;
    这么做就是用 id+标识 当做solr的id使用,如果你需要拿到真的user的id 那就使用uid咯
    ————————————————
    版权声明:本文为CSDN博主「阿胆Amazing」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/wakuangyun/article/details/80684568

  • 相关阅读:
    iOS resign code with App Store profile and post to AppStore
    HTTPS科普扫盲帖 对称加密 非对称加密
    appid 评价
    使用Carthage安装第三方Swift库
    AngularJS:何时应该使用Directive、Controller、Service?
    xcode7 The operation couldn't be completed.
    cocoapods pod install 安装报错 is not used in any concrete target
    xcode7 NSAppTransportSecurity
    learning uboot how to set ddr parameter in qca4531 cpu
    learning uboot enable protect console
  • 原文地址:https://www.cnblogs.com/wangwenlong8/p/13021975.html
Copyright © 2020-2023  润新知