0

GRAILS アプリケーションを開発しています (私は GRAILS を初めて使用し、前の開発者からプロジェクトを継承しました)。GRAILS がどのように動作するか、DOMAIN クラスや休止状態などの使用法について少しずつ理解しています。MySQL データベースは 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% を使用していましたが、検索語がより大きな単語の一部であるカテゴリを検索します (たとえば、'caravan') - 残念ながら、rlike は何も返しませんユーザーが「車」をリクエストした場合。

私はコードを編集しました - Igor が最初に「domainName」の奇妙なインクルージョンを指摘したように。これは、ユーザーが特定のドメイン (例: 「example.com」) の URL のみをフィルタリングできるようにするために渡されるオプションのパラメーターです。

4

2 に答える 2

0

1) (従来のデータベース構造に基づくのではなく) スクラッチから開発された Grails アプリケーションの場合、ドメイン クラスCategoryTarget、が既にあるはずUrlMetaDataです (それ以外の場合は、手動で作成するか、db-reverse-engineer プラグインを使用して作成する必要があります)。

2)フィールドがありTarget、フィールドがあると仮定しますCategory categoryCategoryUrlMetaData 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 に答える
0

特定のドメイン オブジェクトの空のリストを作成し、resultsList をループして、各行からドメイン オブジェクトを作成し、それらのオブジェクトのリストに追加します。次に、そのリストをコントローラーからビューに返します。それはあなたが探しているものですか?

于 2012-09-28T20:40:42.323 に答える