Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 134
Search Tags + Update#38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
a111a13
Functioning tag search
hareeshnagaraj 534c347
NITS
hareeshnagaraj 4b7cdcd
ts search update
hareeshnagaraj 8abce32
New migration
hareeshnagaraj fece7a8
tmp
hareeshnagaraj 9e43d46
Merge branch 'hn_search_2' into hn_search_update
hareeshnagaraj bc0ac86
follower count
hareeshnagaraj 8b13e05
CHECKPOINT - play count in progress
hareeshnagaraj c0598b8
Play count now sorted
hareeshnagaraj 3384d56
Fix .env
hareeshnagaraj a2977f4
Pagination added
hareeshnagaraj 7be39b1
Tags only search function exposed
hareeshnagaraj dd6628b
NIT
hareeshnagaraj 989ed52
comm
hareeshnagaraj b8b23f8
hard nit
hareeshnagaraj 7c9beb6
Deleted stale
hareeshnagaraj 4e3f74a
Revert 'is' in favor of '=='
hareeshnagaraj 8a18a88
Remove 'tags' from users query
hareeshnagaraj b452a46
Default user tags to 2
hareeshnagaraj 2cb4dee
Paginate users
hareeshnagaraj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46 discovery-provider/alembic/versions/e9a9c6c2e3b7_track_view_update.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """track view update | ||
| Revision ID: e9a9c6c2e3b7 | ||
| Revises: 3acec9065c7f | ||
| Create Date: 2019-09-06 10:55:19.835973 | ||
| """ | ||
| from alembic import op | ||
| import sqlalchemy as sa | ||
| # revision identifiers, used by Alembic. | ||
| revision = 'e9a9c6c2e3b7' | ||
| down_revision = '3acec9065c7f' | ||
| branch_labels = None | ||
| depends_on = None | ||
| def upgrade(): | ||
| connection = op.get_bind() | ||
| connection.execute(''' | ||
| --- Update track_lexeme_dict to exclude tags as part of search | ||
| DROP MATERIALIZED VIEW track_lexeme_dict; | ||
| DROP INDEX IF EXISTS track_words_idx; | ||
| CREATE MATERIALIZED VIEW track_lexeme_dict as | ||
| SELECT * FROM ( | ||
| SELECT | ||
| t.track_id, | ||
| unnest(tsvector_to_array(to_tsvector('audius_ts_config', replace(COALESCE(t."title", ''), '&', 'and')))) | ||
| as word | ||
| FROM | ||
| "tracks" t | ||
| INNER JOIN "users" u ON t."owner_id" = u."user_id" | ||
| WHERE t."is_current" = true and u."is_ready" = true and u."is_current" = true | ||
| GROUP BY t."track_id", t."title", t."tags" | ||
| ) AS words; | ||
| -- add index on above materialized view | ||
| CREATE INDEX track_words_idx ON track_lexeme_dict USING gin(word gin_trgm_ops); | ||
| ''') | ||
| # ### end Alembic commands ### | ||
| def downgrade(): | ||
| pass | ||
| # ### end Alembic commands ### |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,15 @@ | ||
| import logging # pylint: disable=C0302 | ||
| import requests | ||
| from sqlalchemy import func, desc | ||
| from urllib.parse import urljoin | ||
| from flask import request | ||
| from src import exceptions | ||
| from src.queries import response_name_constants | ||
| from src.models import Track, Repost, RepostType, Follow, Playlist, Save, SaveType | ||
| from src.utils import helpers | ||
| from src.utils.config import shared_config | ||
| logger = logging.getLogger(__name__) | ||
| @@ -501,6 +504,56 @@ def get_save_counts(session, query_by_user_flag, query_save_type_flag, filter_id | ||
| return save_counts_query.all() | ||
| def get_followee_count_dict(session, user_ids): | ||
| # build dict of user id --> followee count | ||
| followee_counts = ( | ||
| session.query( | ||
| Follow.follower_user_id, | ||
| func.count(Follow.follower_user_id) | ||
| ) | ||
| .filter( | ||
| Follow.is_current == True, | ||
| Follow.is_delete == False, | ||
| Follow.follower_user_id.in_(user_ids) | ||
| ) | ||
| .group_by(Follow.follower_user_id) | ||
| .all() | ||
| ) | ||
| followee_count_dict = {user_id: followee_count for (user_id, followee_count) in followee_counts} | ||
| return followee_count_dict | ||
| def get_track_play_counts(track_ids): | ||
| identity_url = shared_config['discprov']['identity_service_url'] | ||
hareeshnagaraj marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| querystring = {} | ||
| key_str = "id[{}]" | ||
| index = 0 | ||
| # Generate track listen query dict with format id[0]=x, id[1]=y, etc. | ||
| for track_id in track_ids: | ||
| key = key_str.format(index) | ||
| index += 1 | ||
| querystring[key] = str(track_id) | ||
| # Create and query identity service endpoint | ||
| identity_tracks_endpoint = urljoin(identity_url, 'tracks/listens') | ||
| resp = requests.get(identity_tracks_endpoint, params=querystring) | ||
| json_resp = resp.json() | ||
| keys = list(resp.json().keys()) | ||
| # Scenario should never arise, since we don't impose date parameter on initial query | ||
| if len(keys) != 1: | ||
| raise Exception('Invalid number of keys') | ||
| # Parse listen query results into track listen count dictionary | ||
| date_key = keys[0] | ||
| listen_count_json = json_resp[date_key] | ||
| track_listen_counts = {} | ||
| if 'listenCounts' in listen_count_json: | ||
| for listen_info in listen_count_json['listenCounts']: | ||
| current_id = listen_info['trackId'] | ||
| track_listen_counts[current_id] = listen_info['listens'] | ||
| return track_listen_counts | ||
| def get_pagination_vars(): | ||
| limit = min( | ||
| max(request.args.get("limit", default=defaultLimit, type=int), minLimit), | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,10 +6,13 @@ | ||
| from src import api_helpers, exceptions | ||
| from src.models import User, Track, RepostType, Playlist, SaveType | ||
| from src.utils import helpers | ||
| from src.utils.config import shared_config | ||
| from src.utils.db_session import get_db | ||
| from src.queries import response_name_constants | ||
| from src.queries.query_helpers import get_current_user_id, populate_user_metadata, \ | ||
| populate_track_metadata, populate_playlist_metadata, get_pagination_vars | ||
| populate_track_metadata, populate_playlist_metadata, get_pagination_vars, \ | ||
| get_followee_count_dict, get_track_play_counts | ||
| logger = logging.getLogger(__name__) | ||
| bp = Blueprint("search_queries", __name__) | ||
| @@ -40,6 +43,145 @@ def search_full(): | ||
| def search_autocomplete(): | ||
| return search(True) | ||
| @bp.route("/search/tags", methods=("GET",)) | ||
| def search_tags(): | ||
| logger.warning('search tags working') | ||
| search_str = request.args.get("query", type=str) | ||
| if not search_str: | ||
| raise exceptions.ArgumentError("Invalid value for parameter 'query'") | ||
| user_tag_count = request.args.get("user_tag_count", type=str) | ||
| if not user_tag_count: | ||
| user_tag_count = "2" | ||
| (limit, offset) = get_pagination_vars() | ||
| like_tags_str = str.format('%{}%', search_str) | ||
| db = get_db() | ||
| with db.scoped_session() as session: | ||
| track_res = sqlalchemy.text( | ||
| f""" | ||
| select distinct(track_id) | ||
| from | ||
| ( | ||
| select | ||
| strip(to_tsvector(tracks.tags)) as tagstrip, | ||
| track_id | ||
| from | ||
| tracks | ||
| where | ||
| (tags like :like_tags_query) | ||
| and (is_current is true) | ||
| and (is_delete is false) | ||
| order by | ||
| updated_at desc | ||
| ) as t | ||
| where | ||
| tagstrip @@ to_tsquery(:query); | ||
| """ | ||
| ) | ||
| user_res = sqlalchemy.text( | ||
| f""" | ||
| select * from | ||
| ( | ||
| select | ||
| count(track_id), | ||
| owner_id | ||
| from | ||
| ( | ||
| select | ||
| strip(to_tsvector(tracks.tags)) as tagstrip, | ||
| track_id, | ||
| owner_id | ||
| from | ||
| tracks | ||
| where | ||
| (tags like :like_tags_query) | ||
| and (is_current is true) | ||
| order by | ||
| updated_at desc | ||
| ) as t | ||
| where | ||
| tagstrip @@ to_tsquery(:query) | ||
| group by | ||
| owner_id | ||
| order by | ||
| count desc | ||
| ) as usr | ||
| where | ||
| usr.count > :user_tag_count; | ||
| """ | ||
| ) | ||
| track_ids = session.execute( | ||
| track_res, | ||
| { | ||
| "query":search_str, | ||
| "like_tags_query":like_tags_str | ||
| } | ||
| ).fetchall() | ||
| user_ids = session.execute( | ||
| user_res, | ||
| { | ||
| "query":search_str, | ||
| "like_tags_query":like_tags_str, | ||
| "user_tag_count": user_tag_count | ||
| } | ||
| ).fetchall() | ||
| # track_ids is list of tuples - simplify to 1-D list | ||
| track_ids = [i[0] for i in track_ids] | ||
| # user_ids is list of tuples - simplify to 1-D list | ||
| user_ids = [i[1] for i in user_ids] | ||
| followee_count_dict = get_followee_count_dict(session, user_ids) | ||
| tracks = ( | ||
| session.query(Track) | ||
| .filter( | ||
| Track.is_current == True, | ||
| Track.is_delete == False, | ||
| Track.track_id.in_(track_ids), | ||
| ) | ||
| .all() | ||
| ) | ||
| tracks = helpers.query_result_to_list(tracks) | ||
| track_play_counts = get_track_play_counts(track_ids) | ||
| users = ( | ||
| session.query(User) | ||
| .filter( | ||
| User.is_current == True, | ||
| User.is_ready == True, | ||
| User.user_id.in_(user_ids) | ||
| ) | ||
| .all() | ||
| ) | ||
| users = helpers.query_result_to_list(users) | ||
| for user in users: | ||
| user_id = user["user_id"] | ||
| user[response_name_constants.follower_count] = followee_count_dict.get(user_id, 0) | ||
| followee_sorted_users = \ | ||
| sorted(users, key=lambda i: i[response_name_constants.follower_count], reverse=True) | ||
| for track in tracks: | ||
| track_id = track["track_id"] | ||
| track[response_name_constants.play_count] = track_play_counts.get(track_id, 0) | ||
| play_count_sorted_tracks = \ | ||
| sorted(tracks, key=lambda i: i[response_name_constants.play_count], reverse=True) | ||
| # Add pagination parameters to track and user results | ||
| play_count_sorted_tracks = \ | ||
hareeshnagaraj marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| play_count_sorted_tracks[slice(offset, offset + limit, 1)] | ||
| followee_sorted_users = \ | ||
| followee_sorted_users[slice(offset, offset + limit, 1)] | ||
| resp = {} | ||
| resp['tracks'] = play_count_sorted_tracks | ||
| resp['users'] = followee_sorted_users | ||
| return api_helpers.success_response(resp) | ||
| # SEARCH QUERIES | ||
| # We chose to use the raw SQL instead of SQLAlchemy because we're pushing SQLAlchemy to it's | ||
| # limit to do this query by creating new wrappers for pg functions that do not exist like | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.