Commit bd891c21 by E. Kolpakov

Added setting to enable/disable library indexing + moved is_index_enabled into…

Added setting to enable/disable library indexing + moved is_index_enabled into search indexer classes
Added task and signal to fire library reindex
parent eb7c5be0
...@@ -10,9 +10,6 @@ from eventtracking import tracker ...@@ -10,9 +10,6 @@ from eventtracking import tracker
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from search.search_engine_base import SearchEngine from search.search_engine_base import SearchEngine
from opaque_keys.edx.locator import CourseLocator, LibraryLocator
# REINDEX_AGE is the default amount of time that we look back for changes # REINDEX_AGE is the default amount of time that we look back for changes
# that might have happened. If we are provided with a time at which the # that might have happened. If we are provided with a time at which the
# indexing is triggered, then we know it is safe to only index items # indexing is triggered, then we know it is safe to only index items
...@@ -23,13 +20,6 @@ REINDEX_AGE = timedelta(0, 60) # 60 seconds ...@@ -23,13 +20,6 @@ REINDEX_AGE = timedelta(0, 60) # 60 seconds
log = logging.getLogger('edx.modulestore') log = logging.getLogger('edx.modulestore')
def indexing_is_enabled():
"""
Checks to see if the indexing feature is enabled
"""
return settings.FEATURES.get('ENABLE_COURSEWARE_INDEX', False)
class SearchIndexingError(Exception): class SearchIndexingError(Exception):
""" Indicates some error(s) occured during indexing """ """ Indicates some error(s) occured during indexing """
...@@ -45,6 +35,7 @@ class SearchIndexBase(object): ...@@ -45,6 +35,7 @@ class SearchIndexBase(object):
INDEX_NAME = None INDEX_NAME = None
DOCUMENT_TYPE = None DOCUMENT_TYPE = None
ENABLE_INDEXING_KEY = None
INDEX_EVENT = { INDEX_EVENT = {
'name': None, 'name': None,
...@@ -52,6 +43,13 @@ class SearchIndexBase(object): ...@@ -52,6 +43,13 @@ class SearchIndexBase(object):
} }
@classmethod @classmethod
def indexing_is_enabled(cls):
"""
Checks to see if the indexing feature is enabled
"""
return settings.FEATURES.get(cls.ENABLE_INDEXING_KEY, False)
@classmethod
def _fetch_top_level(self, modulestore, structure_key): def _fetch_top_level(self, modulestore, structure_key):
""" Fetch the item from the modulestore location """ """ Fetch the item from the modulestore location """
raise NotImplementedError("Should be overridden in child classes") raise NotImplementedError("Should be overridden in child classes")
...@@ -220,6 +218,7 @@ class SearchIndexBase(object): ...@@ -220,6 +218,7 @@ class SearchIndexBase(object):
class CoursewareSearchIndexer(SearchIndexBase): class CoursewareSearchIndexer(SearchIndexBase):
INDEX_NAME = "courseware_index" INDEX_NAME = "courseware_index"
DOCUMENT_TYPE = "courseware_content" DOCUMENT_TYPE = "courseware_content"
ENABLE_INDEXING_KEY = 'ENABLE_COURSEWARE_INDEX'
INDEX_EVENT = { INDEX_EVENT = {
'name': 'edx.course.index.reindexed', 'name': 'edx.course.index.reindexed',
...@@ -247,6 +246,7 @@ class CoursewareSearchIndexer(SearchIndexBase): ...@@ -247,6 +246,7 @@ class CoursewareSearchIndexer(SearchIndexBase):
class LibrarySearchIndexer(SearchIndexBase): class LibrarySearchIndexer(SearchIndexBase):
INDEX_NAME = "library_index" INDEX_NAME = "library_index"
DOCUMENT_TYPE = "library_content" DOCUMENT_TYPE = "library_content"
ENABLE_INDEXING_KEY = 'ENABLE_LIBRARY_INDEX'
INDEX_EVENT = { INDEX_EVENT = {
'name': 'edx.library.index.reindexed', 'name': 'edx.library.index.reindexed',
......
...@@ -5,7 +5,7 @@ from pytz import UTC ...@@ -5,7 +5,7 @@ from pytz import UTC
from django.dispatch import receiver from django.dispatch import receiver
from xmodule.modulestore.django import SignalHandler from xmodule.modulestore.django import SignalHandler
from contentstore.courseware_index import indexing_is_enabled from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer
@receiver(SignalHandler.course_published) @receiver(SignalHandler.course_published)
...@@ -15,5 +15,16 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable= ...@@ -15,5 +15,16 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=
""" """
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
from .tasks import update_search_index from .tasks import update_search_index
if indexing_is_enabled(): if CoursewareSearchIndexer.indexing_is_enabled():
update_search_index.delay(unicode(course_key), datetime.now(UTC).isoformat()) update_search_index.delay(unicode(course_key), datetime.now(UTC).isoformat())
@receiver(SignalHandler.library_updated)
def listen_for_course_publish(sender, library_key, **kwargs): # pylint: disable=unused-argument
"""
Receives signal and kicks off celery task to update search index
"""
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
from .tasks import update_library_index
if LibrarySearchIndexer.indexing_is_enabled():
update_library_index.delay(unicode(library_key), datetime.now(UTC).isoformat())
...@@ -10,7 +10,7 @@ from pytz import UTC ...@@ -10,7 +10,7 @@ from pytz import UTC
from django.contrib.auth.models import User from django.contrib.auth.models import User
from contentstore.courseware_index import CoursewareSearchIndexer, SearchIndexingError from contentstore.courseware_index import CoursewareSearchIndexer, LibrarySearchIndexer, SearchIndexingError
from contentstore.utils import initialize_permissions from contentstore.utils import initialize_permissions
from course_action_state.models import CourseRerunState from course_action_state.models import CourseRerunState
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
...@@ -98,3 +98,15 @@ def update_search_index(course_id, triggered_time_isoformat): ...@@ -98,3 +98,15 @@ def update_search_index(course_id, triggered_time_isoformat):
LOGGER.error('Search indexing error for complete course %s - %s', course_id, unicode(exc)) LOGGER.error('Search indexing error for complete course %s - %s', course_id, unicode(exc))
else: else:
LOGGER.debug('Search indexing successful for complete course %s', course_id) LOGGER.debug('Search indexing successful for complete course %s', course_id)
@task()
def update_library_index(library_id, triggered_time):
""" Updates course search index. """
try:
library_key = CourseKey.from_string(library_id)
LibrarySearchIndexed.indexindex_course(modulestore(), library_key, triggered_at=triggered_time)
except SearchIndexingError as exc:
LOGGER.error('Search indexing error for library %s - %s', library_id, unicode(exc))
else:
LOGGER.debug('Search indexing successful for library %s', library_id)
\ No newline at end of file
...@@ -328,7 +328,7 @@ API_DATE_FORMAT = ENV_TOKENS.get('API_DATE_FORMAT', API_DATE_FORMAT) ...@@ -328,7 +328,7 @@ API_DATE_FORMAT = ENV_TOKENS.get('API_DATE_FORMAT', API_DATE_FORMAT)
# Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='} # Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='}
VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {}) VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {})
if FEATURES['ENABLE_COURSEWARE_INDEX']: if FEATURES['ENABLE_COURSEWARE_INDEX'] or FEATURES['ENABLE_LIBRARY_INDEX']:
# Use ElasticSearch for the search engine # Use ElasticSearch for the search engine
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
......
...@@ -78,6 +78,7 @@ YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT) ...@@ -78,6 +78,7 @@ YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT)
YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT) YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT)
FEATURES['ENABLE_COURSEWARE_INDEX'] = True FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = True
SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine"
# Path at which to store the mock index # Path at which to store the mock index
MOCK_SEARCH_BACKING_FILE = ( MOCK_SEARCH_BACKING_FILE = (
......
...@@ -140,6 +140,9 @@ FEATURES = { ...@@ -140,6 +140,9 @@ FEATURES = {
# Enable the courseware search functionality # Enable the courseware search functionality
'ENABLE_COURSEWARE_INDEX': False, 'ENABLE_COURSEWARE_INDEX': False,
# Enable content libraries search functionality
'ENABLE_LIBRARY_INDEX': False,
# Enable course reruns, which will always use the split modulestore # Enable course reruns, which will always use the split modulestore
'ALLOW_COURSE_RERUNS': True, 'ALLOW_COURSE_RERUNS': True,
......
...@@ -80,6 +80,7 @@ FEATURES['ENTRANCE_EXAMS'] = True ...@@ -80,6 +80,7 @@ FEATURES['ENTRANCE_EXAMS'] = True
################################ SEARCH INDEX ################################ ################################ SEARCH INDEX ################################
FEATURES['ENABLE_COURSEWARE_INDEX'] = True FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = True
SEARCH_ENGINE = "search.elastic.ElasticSearchEngine" SEARCH_ENGINE = "search.elastic.ElasticSearchEngine"
############################################################################### ###############################################################################
......
...@@ -267,6 +267,7 @@ VIDEO_CDN_URL = { ...@@ -267,6 +267,7 @@ VIDEO_CDN_URL = {
# Courseware Search Index # Courseware Search Index
FEATURES['ENABLE_COURSEWARE_INDEX'] = True FEATURES['ENABLE_COURSEWARE_INDEX'] = True
FEATURES['ENABLE_LIBRARY_INDEX'] = True
SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine"
# Dummy secret key for dev/test # Dummy secret key for dev/test
......
...@@ -80,9 +80,11 @@ class SignalHandler(object): ...@@ -80,9 +80,11 @@ class SignalHandler(object):
""" """
course_published = django.dispatch.Signal(providing_args=["course_key"]) course_published = django.dispatch.Signal(providing_args=["course_key"])
library_updated = django.dispatch.Signal(providing_args=["library_key"])
_mapping = { _mapping = {
"course_published": course_published "course_published": course_published,
"library_updated": library_updated
} }
def __init__(self, modulestore_class): def __init__(self, modulestore_class):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment