2014-11-20 77 views
2

我想通過關鍵詞搜索以下Episode模型。 Episode有一個多對多的關係_key_words將一集連接到EpisodeKeywordEpisodeKeyword代表可以搜索的單詞。該查詢如何按關鍵字匹配的數量進行排序?

class Episode(db.Model): 
    _key_words = db.relationship('EpisodeKeyword', 
     secondary = KeywordEpisode, 
     primaryjoin = _id==KeywordEpisode.c.feed_id, 
     secondaryjoin = EpisodeKeyword._id==KeywordEpisode.c.keyword_id, 
     backref = db.backref('episodes', lazy = 'dynamic'), 
     lazy = 'dynamic') 


class EpisodeKeyword(db.Model): 
    ''' 
    A keyword for an Episode 
    ''' 
    __table_args__ = {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8mb4'} 

    DB_MAX_WORD_LENGTH = 30 
    _id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    _word = db.Column(db.String(DB_MAX_WORD_LENGTH), index = True, unique=True) 


KeywordEpisode = db.Table('episode_keywords', 
     db.Column('feed_id', db.Integer, db.ForeignKey('episode._id'),index = True), 
     db.Column('keyword_id', db.Integer, db.ForeignKey('episode_keyword._id'),index = True) 
    ) 

搜索條件拆分得到的關鍵字列表進行搜索:

user_input = 'oct 2014' 
search_keywords = ['oct', '2014'] 

我可以用得到的結果的列表:

results = db.session.query(Episode).filter(EpisodeKeyword._word.in_(words)).join(Episode._key_words).join(Episode).all() 

不過,我也想按匹配關鍵字的數量排序結果。例如,如果Episode._key_words同時具有「oct」和「2014」,它應該出現在只有一個關鍵字匹配的項目之前。什麼是將完成這個查詢?

回答

2

使用子查詢來篩選和計算關鍵字,然後將其加入到最終查詢中。

# split the query into a list 
search = 'oct 2014' 
words = search.strip().split() 

# use an unnest subquery instead of directly passing the list to in_ 
# this is for performance reasons for large lists of keywords 
words_tab = db.session.query(db.func.unnest(words).label('word')).subquery() 

# count the words that match for each episode as a subquery 
# this also does the filtering since we're doing the join here 
words_q = db.session.query(
    Episode.id, 
    db.func.count(Episode.id).label('words') 
).join(Episode._key_words 
).filter(EpisodeKeyword._word.in_(words_tab) 
).group_by(Episode.id 
).subquery() 

# join on the word query and order by its counts 
results = Episode.query.join(
    (words_q, words_q.c.id == Episode.id) 
).order_by(words_q.c.words.desc() 
).all() 
相關問題