0

我正在开发一个 GRAILS 应用程序(我是 GRAILS 的新手,并且从以前的开发人员那里继承了该项目)。我正在慢慢掌握 GRAILS 的运行方式以及 DOMAIN 类、休眠等的使用。MySQL db 托管在 Amazon 上,我们正在使用 ElasticCache。

你们中的任何一个知识渊博的人都知道我可以如何将以下 SQL 语句转换为域类和查询条件。

if(params?.searchterm) {

    def searchTerms = params.searchterm.trim().split( ',' )
    def resultLimit = params.resultlimit?: 1000
    def addDomain = ''

    if (params?.domainname){
        addDomain = " and url like '%${params.domainname}%' "
    }

    def theSearchTermsSQL = ""

    /*
     *  create c.name rlike condition for each search term
     *
     */
    searchTerms.each{
        aSearchTerm -> 
            if( theSearchTermsSQL != '' ){
                theSearchTermsSQL += ' or '
            }
            theSearchTermsSQL += "cname rlike '[[:<:]]" + aSearchTerm.trim() +  "[[:>:]]'"
    }

    /*
     *  build query
     *
     */
    def getUrlsQuery = "select
        u.url as url,
        c.name as cname,
        t.weight as tweight
    from
       (category c, target t, url_meta_data u )
    where
       (" + theSearchTermsSQL + ")
    and 
        t.category_id = c.id
        and t.url_meta_data_id = u.id
        and u.ugc_flag != 1 " + addDomain + "
    order by tweight desc
    limit " + resultLimit.toLong()


    /* 
     *  run query
     *
     */
    Sql sqlInstance = new Sql( dataSource )

    def resultsList = sqlInstance.rows( getUrlsQuery )

}

表格如下(虚拟数据):

[Category]
id | name
-----------
 1 | small car
 2 | bike
 3 | truck
 4 | train
 5 | plane
 6 | large car
 7 | caravan

[Target]
id | cid | weight | url_meta_data_id
----------------------------------------
 1 |  1  |  56    |        1
 2 |  1  |  76    |        2
 3 |  3  |  34    |        3
 4 |  2  |  98    |        4
 5 |  1  |  11    |        5
 6 |  3  |  31    |        7
 7 |  5  |  12    |        8
 8 |  4  |  82    |        6

[url_meta_data]
id | url                          | ugc_flag
---------------------------------------------
 1 | http://www.example.com/foo/1 |    0
 2 | http://www.example.com/foo/2 |    0
 3 | http://www.example.com/foo/3 |    1
 4 | http://www.example.com/foo/4 |    0
 5 | http://www.example.com/foo/5 |    1
 6 | http://www.example.com/foo/6 |    1
 7 | http://www.example.com/foo/7 |    1
 8 | http://www.example.com/foo/8 |    0

领域类

class Category {

    static hasMany = [targets: Target]

    static mapping = {
        cache  true
        cache usage: 'read-only'
        targetConditions cache : true
    }

    String name

    String source
}

class Target {

    static belongsTo = [urlMetaData: UrlMetaData, category: Category]
    static mapping = {
        cache true
        cache usage: 'read-only'
    }

    int weight

}

class UrlMetaData {

    String url

    String ugcFlag

    static hasMany = [targets: Target ]

    static mapping = { 
        cache true
        cache usage: 'read-only'
    }

    static transients = ['domainName']

    String getDomainName() {

        return HostnameHelper.getBaseDomain(url)
    }
}

基本上,来自 url_meta_data 的 url 可以关联到许多类别。所以本质上我想要实现的应该是一个相对基本的操作......返回搜索词“汽车”的所有网址、它们的权重(即重要性)以及 ugc_flag 不是 1 的位置(即 url不是用户生成的内容)。数据库中有 100K + 记录,这些记录是从第三方提供商导入的。请注意,所有 URL 都属于我的客户 - 这里没有做任何狡猾的事情。

请注意我在查询中使用的 rlike - 我最初使用的是 ilike %searchterm% 但它会找到 searchterm 是较大单词一部分的类别,例如“caravan”) - 不幸的是,尽管 rlike 不会返回任何内容如果用户请求“汽车”。

我编辑了代码 - 正如 Igor 指出最初包含“域名”的奇怪内容。这是传递的可选参数,允许用户仅过滤特定域的 url(例如“example.com”)

4

2 回答 2

0

我会创建一个给定域对象的空列表,遍历结果列表,从每一行构造一个域对象并将其添加到这些对象的列表中。然后将该列表从控制器返回以查看。那是你要找的吗?

于 2012-09-28T20:40:42.323 回答
0

1) 如果它是从头开发的 Grails 应用程序(而不是基于遗留数据库结构),那么您可能应该已经有域类Category, Target, UrlMetaData(否则您必须手动创建它们或使用 db-reverse-engineer 插件)

2)我假设Target有一个领域Category category并且Category有一个领域UrlMetaData urlMetaData

3)要走的路可能是http://grails.org/doc/2.1.0/ref/Domain%20Classes/createCriteria.html,我将尝试为您的特定案例概述基础知识

4)不确定是什么theDomain意思 - 可能是代码异味,以及接受rlike来自客户端的参数

5)以下代码根本没有经过测试 - 特别是我不确定嵌套条件内的析取如何工作。但这可能是一个合适的起点;记录 sql 查询应该有助于使其工作(如何在 Grails 中记录 SQL 语句

def c = Target.createCriteria() //create criteria on Target
def resultsList = c.list(max: resultLimit.toLong()) { //list all matched entities up to resultLimit results
    category { //nested criteria for category
        //the following 'if' statement and its body is plain Groovy code rather than part of DSL that translates to Hibernate Criteria
        if (searchTerms) { //do the following only if searchTerms list is not empty
            or { // one of several conditions
                for (st in searchTerms) { // not a part of DSL - plain Groovy loop
                    rlike('name', st.trim())) //add a disjunction element
                }
            }
        }
        urlMetaData { //nested criteria for metadata
            ne('ugcFlag', 1) //ugcFlag not equal 1
        }
    }    
    order('weight', 'desc') //order by weight
}

明确编写时,限制可能or效果更好

if (searchTerms) { 
    def r = Restrictions.disjunction() 
    for (st in searchTerms) {
        r.add(new LikeExpression('name', st.trim()))
    }
    instance.add(r) //'instance' is an injected property
}

干杯,
伊戈尔·西内夫

于 2012-09-29T19:49:15.690 回答