I've been working on a dynamic question-and-answers system, but I'm having trouble creating a efficient AND flexible design for this system. I'd love to know if there's an established design pattern or any recommendations for designing this system.
我一直在研究一个动态的问答系统,但是我在为这个系统创建一个高效灵活的设计时遇到了麻烦。我很想知道是否有既定的设计模式或任何设计该系统的建议。
What I'm trying to do
I have a set of questions. After answering them, another set of questions are shown, depending on the answers to the previous set. This repeats, until no more questions are needed.
我有一系列问题。在回答之后,将显示另一组问题,具体取决于前一组的答案。这个重复,直到不再需要问题为止。
The question answers are all boolean, multiple-choice, or numeric.
问题的答案都是布尔值,多项选择或数字。
The important part is that most questions are only shown when a specific set of criteria is met, based on the previous answers.
I need the criteria to support mainly boolean logic, such as And, Or, Not, Equals, Greater Than, and Less Than.
重要的是,大多数问题仅在满足一组特定标准时显示,并基于之前的答案。我需要标准来支持主要的布尔逻辑,例如And,Or,Not,Equals,Greater Than和Less Than。
For example, let's say I have already received answers to questions such as Age
, Gender
, and State
.
One of the next questions is In School?
, but it should ONLY be displayed if: Age < 30 AND Gender=Male AND (State = CA OR State = NY)
例如,假设我已经收到了诸如年龄,性别和州等问题的答案。接下来的问题之一是In School?,但只有在以下情况下才能显示:年龄<30且性别=男性AND(州= CA OR州= NY)
Has anyone heard of a similar design pattern? How would you approach this design?
Background Information
I tried Database columns
At first, we only had 3 initial questions, so we just used 3 columns to filter the second set of questions.
起初,我们只有3个初始问题,因此我们只使用3列来过滤第二组问题。
However, our business needs grew and we started needing more initial questions, added more columns, and put more logic within those filters.
但是,我们的业务需求不断增长,我们开始需要更多初始问题,添加更多列,并在这些过滤器中添加更多逻辑。
This quickly became too rigid and cumbersome.
这很快变得太僵硬和麻烦。
I tried a Logic Interpreter
Our second attempt to make the system more flexible: store the filtering logic as JavaScript, and run a JavaScript interpreter to filter the results.
我们第二次尝试使系统更加灵活:将过滤逻辑存储为JavaScript,并运行JavaScript解释器来过滤结果。
This worked pretty well for flexibility, but retrieving thousands of rows from the database and interpreting the scripts was extremely inefficient and performed too poorly for production.
这对于灵活性非常有效,但是从数据库中检索数千行并解释脚本的效率极低,并且对于生产执行效果太差。
I tried a Hybrid
We finally combined the two approaches, and came up with something feasable.
We first filtered our list based on several hard-coded database columns, and further filtered the list with the JavaScript interpreter.
我们最终将这两种方法结合起来,并提出了一些可行的方法。我们首先根据几个硬编码的数据库列过滤我们的列表,然后使用JavaScript解释器进一步过滤列表。
This hybrid system still has many drawbacks:
这种混合系统仍有许多缺点:
- The logic is in 2 different systems (SQL database logic and JavaScript interpreter)
- 逻辑在两个不同的系统中(SQL数据库逻辑和JavaScript解释器)
- Interpreting the JavaScript is slow, and is probably overkill for the simple boolean logic needed
- 解释JavaScript很慢,并且对于所需的简单布尔逻辑可能有点过分
- The system is very difficult to maintain, especially because the JavaScript logic must always be written by a developer.
- 系统很难维护,特别是因为JavaScript逻辑必须始终由开发人员编写。
I'd really like to hear suggestions on how to improve this design.
我真的很想听听如何改进这种设计的建议。
Other Info
My database is MS SQL Server, the backend is .NET C#, and the JavaScript interpreter is JINT. The UI implementation is not important, but is a AJAX enabled website used to ask and answer these questions.
我的数据库是MS SQL Server,后端是.NET C#,JavaScript解释器是JINT。 UI实现并不重要,但它是一个支持AJAX的网站,用于询问和回答这些问题。
3 个解决方案
#1
3
We had to do something similar in the past for a medical system and due to its complexity, we resorted to reuse the rule engine that support multi-classification decision tree. I remember that I came across a nice simple design about this and managed to dig out the link.
我们过去必须为医疗系统做类似的事情,由于其复杂性,我们采用了重用支持多分类决策树的规则引擎。我记得我遇到过一个很简单的设计,并设法挖掘出这个链接。
http://www.javaworld.com/javaworld/javatips/jw-javatip139.html?page=1
http://www.javaworld.com/javaworld/javatips/jw-javatip139.html?page=1
The design is loosely coupled from the data storage, so making it easy to fit into your existing solution design.
设计与数据存储松散耦合,因此可以轻松融入现有的解决方案设计中。
#2
1
If I understand your question correctly, it sounds like you are building a finite state machine.
如果我正确理解你的问题,听起来你正在构建一个有限状态机。
Each state corresponds to a question, and based on the answer you move on to a new question. The same question might occur in several separate states.
每个州对应一个问题,根据答案,您将转到一个新问题。在几个不同的州可能会出现同样的问题。
In your example the begin state would be the question "State?", and if it the answer is "CA" we move to the next state with the question "Rent or Own?". For any answer to that question the next state will be the question "Age?" since there is no further sub-questions for the "State?"->"Rent or Own?" path.
在你的例子中,开始状态是问题“状态?”,如果答案是“CA”,我们会转到下一个状态,问题是“租或自己?”。对于那个问题的任何答案,下一个状态将是“年龄?”的问题。既然“州”没有进一步的子问题? - >“租还是拥?”路径。
For you db model you need a state table and a relation table between states, ie:
对于db模型,您需要状态表和状态之间的关系表,即:
table states:
表状态:
- id (int)
- id(int)
- question (varchar)
- 问题(varchar)
- type (set[text, boolean, int])
- type(set [text,boolean,int])
table state_state:
table state_state:
- fromState (int)
- fromState(int)
- toState(int)
- 使用toState(INT)
- answerType (set[any, equals, greater, ...])
- answerType(设置[any,equals,greater,...])
- answer (varchar)
- 回答(varchar)
In your code you only need to know the current state, ask the question, make a query to state_state and compare the results to the answer given to know what the id of the next state will be and thus the next question.
在您的代码中,您只需要知道当前状态,询问问题,查询state_state并将结果与给出的答案进行比较,以了解下一个状态的id将是什么,从而下一个问题。
If you have a lot of states with the same question you can create a questions table and relate it to state.
如果您有很多具有相同问题的州,您可以创建一个问题表并将其与州相关联。
If you have several 'begin questions' you can either have one state machine and tie the end questions to the next 'begin question', or you could have several state machines.
如果您有几个“开始问题”,您可以拥有一个状态机并将结束问题与下一个“开始问题”联系起来,或者您可以拥有多个状态机。
#3
0
We had a similar requirement to create custom surveys. We have 3 tables, question, response and questionroute. the response table allows you to create multiple answers to each question, and the questionroute table allows you to select the next question based on a specific response.
我们有类似的要求来创建自定义调查。我们有3个表,问题,响应和questionroute。响应表允许您为每个问题创建多个答案,而问题路由表允许您根据特定响应选择下一个问题。
CREATE TABLE [dbo].[Question]
(
QuestionID uniqueidentifier,
[Text] varchar(512)
)
CREATE TABLE [dbo].[Response]
(
ResponseID uniqueidentifier,
QuestionID uniqueidentifier,
[Text] varchar(512)
)
CREATE TABLE [dbo].[QuestionRoute]
(
QuestionRouteID uniqueidentifier,
QuestionID uniqueidentifier,
ResponseID uniqueidentifier,
NextQuestionID uniqueidentifier
)
#1
3
We had to do something similar in the past for a medical system and due to its complexity, we resorted to reuse the rule engine that support multi-classification decision tree. I remember that I came across a nice simple design about this and managed to dig out the link.
我们过去必须为医疗系统做类似的事情,由于其复杂性,我们采用了重用支持多分类决策树的规则引擎。我记得我遇到过一个很简单的设计,并设法挖掘出这个链接。
http://www.javaworld.com/javaworld/javatips/jw-javatip139.html?page=1
http://www.javaworld.com/javaworld/javatips/jw-javatip139.html?page=1
The design is loosely coupled from the data storage, so making it easy to fit into your existing solution design.
设计与数据存储松散耦合,因此可以轻松融入现有的解决方案设计中。
#2
1
If I understand your question correctly, it sounds like you are building a finite state machine.
如果我正确理解你的问题,听起来你正在构建一个有限状态机。
Each state corresponds to a question, and based on the answer you move on to a new question. The same question might occur in several separate states.
每个州对应一个问题,根据答案,您将转到一个新问题。在几个不同的州可能会出现同样的问题。
In your example the begin state would be the question "State?", and if it the answer is "CA" we move to the next state with the question "Rent or Own?". For any answer to that question the next state will be the question "Age?" since there is no further sub-questions for the "State?"->"Rent or Own?" path.
在你的例子中,开始状态是问题“状态?”,如果答案是“CA”,我们会转到下一个状态,问题是“租或自己?”。对于那个问题的任何答案,下一个状态将是“年龄?”的问题。既然“州”没有进一步的子问题? - >“租还是拥?”路径。
For you db model you need a state table and a relation table between states, ie:
对于db模型,您需要状态表和状态之间的关系表,即:
table states:
表状态:
- id (int)
- id(int)
- question (varchar)
- 问题(varchar)
- type (set[text, boolean, int])
- type(set [text,boolean,int])
table state_state:
table state_state:
- fromState (int)
- fromState(int)
- toState(int)
- 使用toState(INT)
- answerType (set[any, equals, greater, ...])
- answerType(设置[any,equals,greater,...])
- answer (varchar)
- 回答(varchar)
In your code you only need to know the current state, ask the question, make a query to state_state and compare the results to the answer given to know what the id of the next state will be and thus the next question.
在您的代码中,您只需要知道当前状态,询问问题,查询state_state并将结果与给出的答案进行比较,以了解下一个状态的id将是什么,从而下一个问题。
If you have a lot of states with the same question you can create a questions table and relate it to state.
如果您有很多具有相同问题的州,您可以创建一个问题表并将其与州相关联。
If you have several 'begin questions' you can either have one state machine and tie the end questions to the next 'begin question', or you could have several state machines.
如果您有几个“开始问题”,您可以拥有一个状态机并将结束问题与下一个“开始问题”联系起来,或者您可以拥有多个状态机。
#3
0
We had a similar requirement to create custom surveys. We have 3 tables, question, response and questionroute. the response table allows you to create multiple answers to each question, and the questionroute table allows you to select the next question based on a specific response.
我们有类似的要求来创建自定义调查。我们有3个表,问题,响应和questionroute。响应表允许您为每个问题创建多个答案,而问题路由表允许您根据特定响应选择下一个问题。
CREATE TABLE [dbo].[Question]
(
QuestionID uniqueidentifier,
[Text] varchar(512)
)
CREATE TABLE [dbo].[Response]
(
ResponseID uniqueidentifier,
QuestionID uniqueidentifier,
[Text] varchar(512)
)
CREATE TABLE [dbo].[QuestionRoute]
(
QuestionRouteID uniqueidentifier,
QuestionID uniqueidentifier,
ResponseID uniqueidentifier,
NextQuestionID uniqueidentifier
)